/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
 * Copyright (C) 2014 University of Washington. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

// DO NOT EDIT THIS FILE. It is automatically generated from CombinedDomains.json
// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py

#include "config.h"
#include "InspectorBackendDispatchers.h"

#include "InspectorFrontendRouter.h"
#include <wtf/JSONValues.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/text/CString.h>

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
#include "InspectorAlternateBackendDispatchers.h"
#endif

namespace Inspector {

ApplicationCacheBackendDispatcherHandler::~ApplicationCacheBackendDispatcherHandler() { }
AuditBackendDispatcherHandler::~AuditBackendDispatcherHandler() { }
#if ENABLE(RESOURCE_USAGE)
CPUProfilerBackendDispatcherHandler::~CPUProfilerBackendDispatcherHandler() { }
#endif // ENABLE(RESOURCE_USAGE)
CSSBackendDispatcherHandler::~CSSBackendDispatcherHandler() { }
CanvasBackendDispatcherHandler::~CanvasBackendDispatcherHandler() { }
ConsoleBackendDispatcherHandler::~ConsoleBackendDispatcherHandler() { }
DOMBackendDispatcherHandler::~DOMBackendDispatcherHandler() { }
DOMDebuggerBackendDispatcherHandler::~DOMDebuggerBackendDispatcherHandler() { }
DOMStorageBackendDispatcherHandler::~DOMStorageBackendDispatcherHandler() { }
DatabaseBackendDispatcherHandler::~DatabaseBackendDispatcherHandler() { }
DebuggerBackendDispatcherHandler::~DebuggerBackendDispatcherHandler() { }
HeapBackendDispatcherHandler::~HeapBackendDispatcherHandler() { }
#if ENABLE(INDEXED_DATABASE)
IndexedDBBackendDispatcherHandler::~IndexedDBBackendDispatcherHandler() { }
#endif // ENABLE(INDEXED_DATABASE)
InspectorBackendDispatcherHandler::~InspectorBackendDispatcherHandler() { }
LayerTreeBackendDispatcherHandler::~LayerTreeBackendDispatcherHandler() { }
#if ENABLE(RESOURCE_USAGE)
MemoryBackendDispatcherHandler::~MemoryBackendDispatcherHandler() { }
#endif // ENABLE(RESOURCE_USAGE)
NetworkBackendDispatcherHandler::~NetworkBackendDispatcherHandler() { }
PageBackendDispatcherHandler::~PageBackendDispatcherHandler() { }
RuntimeBackendDispatcherHandler::~RuntimeBackendDispatcherHandler() { }
ScriptProfilerBackendDispatcherHandler::~ScriptProfilerBackendDispatcherHandler() { }
ServiceWorkerBackendDispatcherHandler::~ServiceWorkerBackendDispatcherHandler() { }
TargetBackendDispatcherHandler::~TargetBackendDispatcherHandler() { }
TimelineBackendDispatcherHandler::~TimelineBackendDispatcherHandler() { }
WorkerBackendDispatcherHandler::~WorkerBackendDispatcherHandler() { }

Ref<ApplicationCacheBackendDispatcher> ApplicationCacheBackendDispatcher::create(BackendDispatcher& backendDispatcher, ApplicationCacheBackendDispatcherHandler* agent)
{
    return adoptRef(*new ApplicationCacheBackendDispatcher(backendDispatcher, agent));
}

ApplicationCacheBackendDispatcher::ApplicationCacheBackendDispatcher(BackendDispatcher& backendDispatcher, ApplicationCacheBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("ApplicationCache"_s, this);
}

void ApplicationCacheBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<ApplicationCacheBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "getFramesWithManifests")
        getFramesWithManifests(requestId, WTFMove(parameters));
    else if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "getManifestForFrame")
        getManifestForFrame(requestId, WTFMove(parameters));
    else if (method == "getApplicationCacheForFrame")
        getApplicationCacheForFrame(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'ApplicationCache." + method + "' was not found");
}

void ApplicationCacheBackendDispatcher::getFramesWithManifests(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getFramesWithManifests(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::ApplicationCache::FrameWithManifest>> out_frameIds;
    m_agent->getFramesWithManifests(error, out_frameIds);

    if (!error.length())
        result->setArray("frameIds"_s, out_frameIds);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ApplicationCacheBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ApplicationCacheBackendDispatcher::getManifestForFrame(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'ApplicationCache.getManifestForFrame' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getManifestForFrame(requestId, in_frameId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_manifestURL;
    m_agent->getManifestForFrame(error, in_frameId, &out_manifestURL);

    if (!error.length())
        result->setString("manifestURL"_s, out_manifestURL);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ApplicationCacheBackendDispatcher::getApplicationCacheForFrame(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'ApplicationCache.getApplicationCacheForFrame' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getApplicationCacheForFrame(requestId, in_frameId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::ApplicationCache::ApplicationCache> out_applicationCache;
    m_agent->getApplicationCacheForFrame(error, in_frameId, out_applicationCache);

    if (!error.length())
        result->setObject("applicationCache"_s, out_applicationCache);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<AuditBackendDispatcher> AuditBackendDispatcher::create(BackendDispatcher& backendDispatcher, AuditBackendDispatcherHandler* agent)
{
    return adoptRef(*new AuditBackendDispatcher(backendDispatcher, agent));
}

AuditBackendDispatcher::AuditBackendDispatcher(BackendDispatcher& backendDispatcher, AuditBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Audit"_s, this);
}

void AuditBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<AuditBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "setup")
        setup(requestId, WTFMove(parameters));
    else if (method == "run")
        run(requestId, WTFMove(parameters));
    else if (method == "teardown")
        teardown(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Audit." + method + "' was not found");
}

void AuditBackendDispatcher::setup(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool opt_in_contextId_valueFound = false;
    int opt_in_contextId = m_backendDispatcher->getInteger(parameters.get(), "contextId"_s, &opt_in_contextId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Audit.setup' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setup(requestId, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setup(error, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void AuditBackendDispatcher::run(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_test = m_backendDispatcher->getString(parameters.get(), "test"_s, nullptr);
    bool opt_in_contextId_valueFound = false;
    int opt_in_contextId = m_backendDispatcher->getInteger(parameters.get(), "contextId"_s, &opt_in_contextId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Audit.run' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->run(requestId, in_test, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_result;
    Optional<bool> out_wasThrown;
    m_agent->run(error, in_test, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr, out_result, out_wasThrown);

    if (!error.length()) {
        result->setObject("result"_s, out_result);
        if (out_wasThrown.hasValue())
            result->setBoolean("wasThrown"_s, *out_wasThrown);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void AuditBackendDispatcher::teardown(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->teardown(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->teardown(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

#if ENABLE(RESOURCE_USAGE)
Ref<CPUProfilerBackendDispatcher> CPUProfilerBackendDispatcher::create(BackendDispatcher& backendDispatcher, CPUProfilerBackendDispatcherHandler* agent)
{
    return adoptRef(*new CPUProfilerBackendDispatcher(backendDispatcher, agent));
}

CPUProfilerBackendDispatcher::CPUProfilerBackendDispatcher(BackendDispatcher& backendDispatcher, CPUProfilerBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("CPUProfiler"_s, this);
}

void CPUProfilerBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<CPUProfilerBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "startTracking")
        startTracking(requestId, WTFMove(parameters));
    else if (method == "stopTracking")
        stopTracking(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'CPUProfiler." + method + "' was not found");
}

void CPUProfilerBackendDispatcher::startTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->startTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->startTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CPUProfilerBackendDispatcher::stopTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stopTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stopTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}
#endif // ENABLE(RESOURCE_USAGE)

Ref<CSSBackendDispatcher> CSSBackendDispatcher::create(BackendDispatcher& backendDispatcher, CSSBackendDispatcherHandler* agent)
{
    return adoptRef(*new CSSBackendDispatcher(backendDispatcher, agent));
}

CSSBackendDispatcher::CSSBackendDispatcher(BackendDispatcher& backendDispatcher, CSSBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("CSS"_s, this);
}

void CSSBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<CSSBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (CSSBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &CSSBackendDispatcher::enable },
            { "disable", &CSSBackendDispatcher::disable },
            { "getMatchedStylesForNode", &CSSBackendDispatcher::getMatchedStylesForNode },
            { "getInlineStylesForNode", &CSSBackendDispatcher::getInlineStylesForNode },
            { "getComputedStyleForNode", &CSSBackendDispatcher::getComputedStyleForNode },
            { "getAllStyleSheets", &CSSBackendDispatcher::getAllStyleSheets },
            { "getStyleSheet", &CSSBackendDispatcher::getStyleSheet },
            { "getStyleSheetText", &CSSBackendDispatcher::getStyleSheetText },
            { "setStyleSheetText", &CSSBackendDispatcher::setStyleSheetText },
            { "setStyleText", &CSSBackendDispatcher::setStyleText },
            { "setRuleSelector", &CSSBackendDispatcher::setRuleSelector },
            { "createStyleSheet", &CSSBackendDispatcher::createStyleSheet },
            { "addRule", &CSSBackendDispatcher::addRule },
            { "getSupportedCSSProperties", &CSSBackendDispatcher::getSupportedCSSProperties },
            { "getSupportedSystemFontFamilyNames", &CSSBackendDispatcher::getSupportedSystemFontFamilyNames },
            { "forcePseudoState", &CSSBackendDispatcher::forcePseudoState },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'CSS." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void CSSBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getMatchedStylesForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    bool opt_in_includePseudo_valueFound = false;
    bool opt_in_includePseudo = m_backendDispatcher->getBoolean(parameters.get(), "includePseudo"_s, &opt_in_includePseudo_valueFound);
    bool opt_in_includeInherited_valueFound = false;
    bool opt_in_includeInherited = m_backendDispatcher->getBoolean(parameters.get(), "includeInherited"_s, &opt_in_includeInherited_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.getMatchedStylesForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getMatchedStylesForNode(requestId, in_nodeId, opt_in_includePseudo_valueFound ? &opt_in_includePseudo : nullptr, opt_in_includeInherited_valueFound ? &opt_in_includeInherited : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>> out_matchedCSSRules;
    RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::PseudoIdMatches>> out_pseudoElements;
    RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::InheritedStyleEntry>> out_inherited;
    m_agent->getMatchedStylesForNode(error, in_nodeId, opt_in_includePseudo_valueFound ? &opt_in_includePseudo : nullptr, opt_in_includeInherited_valueFound ? &opt_in_includeInherited : nullptr, out_matchedCSSRules, out_pseudoElements, out_inherited);

    if (!error.length()) {
        if (out_matchedCSSRules)
            result->setArray("matchedCSSRules"_s, out_matchedCSSRules);
        if (out_pseudoElements)
            result->setArray("pseudoElements"_s, out_pseudoElements);
        if (out_inherited)
            result->setArray("inherited"_s, out_inherited);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getInlineStylesForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.getInlineStylesForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getInlineStylesForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::CSS::CSSStyle> out_inlineStyle;
    RefPtr<Inspector::Protocol::CSS::CSSStyle> out_attributesStyle;
    m_agent->getInlineStylesForNode(error, in_nodeId, out_inlineStyle, out_attributesStyle);

    if (!error.length()) {
        if (out_inlineStyle)
            result->setObject("inlineStyle"_s, out_inlineStyle);
        if (out_attributesStyle)
            result->setObject("attributesStyle"_s, out_attributesStyle);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getComputedStyleForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.getComputedStyleForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getComputedStyleForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSComputedStyleProperty>> out_computedStyle;
    m_agent->getComputedStyleForNode(error, in_nodeId, out_computedStyle);

    if (!error.length())
        result->setArray("computedStyle"_s, out_computedStyle);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getAllStyleSheets(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getAllStyleSheets(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSStyleSheetHeader>> out_headers;
    m_agent->getAllStyleSheets(error, out_headers);

    if (!error.length())
        result->setArray("headers"_s, out_headers);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getStyleSheet(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_styleSheetId = m_backendDispatcher->getString(parameters.get(), "styleSheetId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.getStyleSheet' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getStyleSheet(requestId, in_styleSheetId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody> out_styleSheet;
    m_agent->getStyleSheet(error, in_styleSheetId, out_styleSheet);

    if (!error.length())
        result->setObject("styleSheet"_s, out_styleSheet);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getStyleSheetText(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_styleSheetId = m_backendDispatcher->getString(parameters.get(), "styleSheetId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.getStyleSheetText' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getStyleSheetText(requestId, in_styleSheetId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_text;
    m_agent->getStyleSheetText(error, in_styleSheetId, &out_text);

    if (!error.length())
        result->setString("text"_s, out_text);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::setStyleSheetText(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_styleSheetId = m_backendDispatcher->getString(parameters.get(), "styleSheetId"_s, nullptr);
    String in_text = m_backendDispatcher->getString(parameters.get(), "text"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.setStyleSheetText' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setStyleSheetText(requestId, in_styleSheetId, in_text);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setStyleSheetText(error, in_styleSheetId, in_text);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::setStyleText(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_styleId = m_backendDispatcher->getObject(parameters.get(), "styleId"_s, nullptr);
    String in_text = m_backendDispatcher->getString(parameters.get(), "text"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.setStyleText' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setStyleText(requestId, *in_styleId, in_text);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::CSS::CSSStyle> out_style;
    m_agent->setStyleText(error, *in_styleId, in_text, out_style);

    if (!error.length())
        result->setObject("style"_s, out_style);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::setRuleSelector(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_ruleId = m_backendDispatcher->getObject(parameters.get(), "ruleId"_s, nullptr);
    String in_selector = m_backendDispatcher->getString(parameters.get(), "selector"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.setRuleSelector' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setRuleSelector(requestId, *in_ruleId, in_selector);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::CSS::CSSRule> out_rule;
    m_agent->setRuleSelector(error, *in_ruleId, in_selector, out_rule);

    if (!error.length())
        result->setObject("rule"_s, out_rule);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::createStyleSheet(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.createStyleSheet' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->createStyleSheet(requestId, in_frameId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_styleSheetId;
    m_agent->createStyleSheet(error, in_frameId, &out_styleSheetId);

    if (!error.length())
        result->setString("styleSheetId"_s, out_styleSheetId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::addRule(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_styleSheetId = m_backendDispatcher->getString(parameters.get(), "styleSheetId"_s, nullptr);
    String in_selector = m_backendDispatcher->getString(parameters.get(), "selector"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.addRule' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->addRule(requestId, in_styleSheetId, in_selector);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::CSS::CSSRule> out_rule;
    m_agent->addRule(error, in_styleSheetId, in_selector, out_rule);

    if (!error.length())
        result->setObject("rule"_s, out_rule);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getSupportedCSSProperties(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getSupportedCSSProperties(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSPropertyInfo>> out_cssProperties;
    m_agent->getSupportedCSSProperties(error, out_cssProperties);

    if (!error.length())
        result->setArray("cssProperties"_s, out_cssProperties);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::getSupportedSystemFontFamilyNames(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getSupportedSystemFontFamilyNames(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<String>> out_fontFamilyNames;
    m_agent->getSupportedSystemFontFamilyNames(error, out_fontFamilyNames);

    if (!error.length())
        result->setArray("fontFamilyNames"_s, out_fontFamilyNames);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CSSBackendDispatcher::forcePseudoState(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    RefPtr<JSON::Array> in_forcedPseudoClasses = m_backendDispatcher->getArray(parameters.get(), "forcedPseudoClasses"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'CSS.forcePseudoState' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->forcePseudoState(requestId, in_nodeId, *in_forcedPseudoClasses);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->forcePseudoState(error, in_nodeId, *in_forcedPseudoClasses);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<CanvasBackendDispatcher> CanvasBackendDispatcher::create(BackendDispatcher& backendDispatcher, CanvasBackendDispatcherHandler* agent)
{
    return adoptRef(*new CanvasBackendDispatcher(backendDispatcher, agent));
}

CanvasBackendDispatcher::CanvasBackendDispatcher(BackendDispatcher& backendDispatcher, CanvasBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Canvas"_s, this);
}

void CanvasBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<CanvasBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (CanvasBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &CanvasBackendDispatcher::enable },
            { "disable", &CanvasBackendDispatcher::disable },
            { "requestNode", &CanvasBackendDispatcher::requestNode },
            { "requestContent", &CanvasBackendDispatcher::requestContent },
            { "requestCSSCanvasClientNodes", &CanvasBackendDispatcher::requestCSSCanvasClientNodes },
            { "resolveCanvasContext", &CanvasBackendDispatcher::resolveCanvasContext },
            { "setRecordingAutoCaptureFrameCount", &CanvasBackendDispatcher::setRecordingAutoCaptureFrameCount },
            { "startRecording", &CanvasBackendDispatcher::startRecording },
            { "stopRecording", &CanvasBackendDispatcher::stopRecording },
            { "requestShaderSource", &CanvasBackendDispatcher::requestShaderSource },
            { "updateShader", &CanvasBackendDispatcher::updateShader },
            { "setShaderProgramDisabled", &CanvasBackendDispatcher::setShaderProgramDisabled },
            { "setShaderProgramHighlighted", &CanvasBackendDispatcher::setShaderProgramHighlighted },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Canvas." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void CanvasBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::requestNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_canvasId = m_backendDispatcher->getString(parameters.get(), "canvasId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.requestNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestNode(requestId, in_canvasId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    int out_nodeId;
    m_agent->requestNode(error, in_canvasId, &out_nodeId);

    if (!error.length())
        result->setInteger("nodeId"_s, out_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::requestContent(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_canvasId = m_backendDispatcher->getString(parameters.get(), "canvasId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.requestContent' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestContent(requestId, in_canvasId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_content;
    m_agent->requestContent(error, in_canvasId, &out_content);

    if (!error.length())
        result->setString("content"_s, out_content);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::requestCSSCanvasClientNodes(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_canvasId = m_backendDispatcher->getString(parameters.get(), "canvasId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.requestCSSCanvasClientNodes' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestCSSCanvasClientNodes(requestId, in_canvasId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<int>> out_clientNodeIds;
    m_agent->requestCSSCanvasClientNodes(error, in_canvasId, out_clientNodeIds);

    if (!error.length())
        result->setArray("clientNodeIds"_s, out_clientNodeIds);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::resolveCanvasContext(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_canvasId = m_backendDispatcher->getString(parameters.get(), "canvasId"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.resolveCanvasContext' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->resolveCanvasContext(requestId, in_canvasId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_object;
    m_agent->resolveCanvasContext(error, in_canvasId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, out_object);

    if (!error.length())
        result->setObject("object"_s, out_object);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::setRecordingAutoCaptureFrameCount(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_count = m_backendDispatcher->getInteger(parameters.get(), "count"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.setRecordingAutoCaptureFrameCount' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setRecordingAutoCaptureFrameCount(requestId, in_count);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setRecordingAutoCaptureFrameCount(error, in_count);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::startRecording(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_canvasId = m_backendDispatcher->getString(parameters.get(), "canvasId"_s, nullptr);
    bool opt_in_frameCount_valueFound = false;
    int opt_in_frameCount = m_backendDispatcher->getInteger(parameters.get(), "frameCount"_s, &opt_in_frameCount_valueFound);
    bool opt_in_memoryLimit_valueFound = false;
    int opt_in_memoryLimit = m_backendDispatcher->getInteger(parameters.get(), "memoryLimit"_s, &opt_in_memoryLimit_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.startRecording' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->startRecording(requestId, in_canvasId, opt_in_frameCount_valueFound ? &opt_in_frameCount : nullptr, opt_in_memoryLimit_valueFound ? &opt_in_memoryLimit : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->startRecording(error, in_canvasId, opt_in_frameCount_valueFound ? &opt_in_frameCount : nullptr, opt_in_memoryLimit_valueFound ? &opt_in_memoryLimit : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::stopRecording(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_canvasId = m_backendDispatcher->getString(parameters.get(), "canvasId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.stopRecording' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stopRecording(requestId, in_canvasId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stopRecording(error, in_canvasId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::requestShaderSource(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_programId = m_backendDispatcher->getString(parameters.get(), "programId"_s, nullptr);
    String in_shaderType = m_backendDispatcher->getString(parameters.get(), "shaderType"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.requestShaderSource' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestShaderSource(requestId, in_programId, in_shaderType);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_content;
    m_agent->requestShaderSource(error, in_programId, in_shaderType, &out_content);

    if (!error.length())
        result->setString("content"_s, out_content);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::updateShader(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_programId = m_backendDispatcher->getString(parameters.get(), "programId"_s, nullptr);
    String in_shaderType = m_backendDispatcher->getString(parameters.get(), "shaderType"_s, nullptr);
    String in_source = m_backendDispatcher->getString(parameters.get(), "source"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.updateShader' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->updateShader(requestId, in_programId, in_shaderType, in_source);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->updateShader(error, in_programId, in_shaderType, in_source);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::setShaderProgramDisabled(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_programId = m_backendDispatcher->getString(parameters.get(), "programId"_s, nullptr);
    bool in_disabled = m_backendDispatcher->getBoolean(parameters.get(), "disabled"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.setShaderProgramDisabled' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setShaderProgramDisabled(requestId, in_programId, in_disabled);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setShaderProgramDisabled(error, in_programId, in_disabled);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void CanvasBackendDispatcher::setShaderProgramHighlighted(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_programId = m_backendDispatcher->getString(parameters.get(), "programId"_s, nullptr);
    bool in_highlighted = m_backendDispatcher->getBoolean(parameters.get(), "highlighted"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Canvas.setShaderProgramHighlighted' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setShaderProgramHighlighted(requestId, in_programId, in_highlighted);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setShaderProgramHighlighted(error, in_programId, in_highlighted);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<ConsoleBackendDispatcher> ConsoleBackendDispatcher::create(BackendDispatcher& backendDispatcher, ConsoleBackendDispatcherHandler* agent)
{
    return adoptRef(*new ConsoleBackendDispatcher(backendDispatcher, agent));
}

ConsoleBackendDispatcher::ConsoleBackendDispatcher(BackendDispatcher& backendDispatcher, ConsoleBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Console"_s, this);
}

void ConsoleBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<ConsoleBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "clearMessages")
        clearMessages(requestId, WTFMove(parameters));
    else if (method == "getLoggingChannels")
        getLoggingChannels(requestId, WTFMove(parameters));
    else if (method == "setLoggingChannelLevel")
        setLoggingChannelLevel(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Console." + method + "' was not found");
}

void ConsoleBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ConsoleBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ConsoleBackendDispatcher::clearMessages(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->clearMessages(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->clearMessages(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ConsoleBackendDispatcher::getLoggingChannels(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getLoggingChannels(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Console::Channel>> out_channels;
    m_agent->getLoggingChannels(error, out_channels);

    if (!error.length())
        result->setArray("channels"_s, out_channels);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ConsoleBackendDispatcher::setLoggingChannelLevel(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_source = m_backendDispatcher->getString(parameters.get(), "source"_s, nullptr);
    String in_level = m_backendDispatcher->getString(parameters.get(), "level"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Console.setLoggingChannelLevel' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setLoggingChannelLevel(requestId, in_source, in_level);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setLoggingChannelLevel(error, in_source, in_level);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<DOMBackendDispatcher> DOMBackendDispatcher::create(BackendDispatcher& backendDispatcher, DOMBackendDispatcherHandler* agent)
{
    return adoptRef(*new DOMBackendDispatcher(backendDispatcher, agent));
}

DOMBackendDispatcher::DOMBackendDispatcher(BackendDispatcher& backendDispatcher, DOMBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("DOM"_s, this);
}

void DOMBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<DOMBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (DOMBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "getDocument", &DOMBackendDispatcher::getDocument },
            { "requestChildNodes", &DOMBackendDispatcher::requestChildNodes },
            { "querySelector", &DOMBackendDispatcher::querySelector },
            { "querySelectorAll", &DOMBackendDispatcher::querySelectorAll },
            { "setNodeName", &DOMBackendDispatcher::setNodeName },
            { "setNodeValue", &DOMBackendDispatcher::setNodeValue },
            { "removeNode", &DOMBackendDispatcher::removeNode },
            { "setAttributeValue", &DOMBackendDispatcher::setAttributeValue },
            { "setAttributesAsText", &DOMBackendDispatcher::setAttributesAsText },
            { "removeAttribute", &DOMBackendDispatcher::removeAttribute },
            { "getSupportedEventNames", &DOMBackendDispatcher::getSupportedEventNames },
            { "getDataBindingsForNode", &DOMBackendDispatcher::getDataBindingsForNode },
            { "getAssociatedDataForNode", &DOMBackendDispatcher::getAssociatedDataForNode },
            { "getEventListenersForNode", &DOMBackendDispatcher::getEventListenersForNode },
            { "setEventListenerDisabled", &DOMBackendDispatcher::setEventListenerDisabled },
            { "setBreakpointForEventListener", &DOMBackendDispatcher::setBreakpointForEventListener },
            { "removeBreakpointForEventListener", &DOMBackendDispatcher::removeBreakpointForEventListener },
            { "getAccessibilityPropertiesForNode", &DOMBackendDispatcher::getAccessibilityPropertiesForNode },
            { "getOuterHTML", &DOMBackendDispatcher::getOuterHTML },
            { "setOuterHTML", &DOMBackendDispatcher::setOuterHTML },
            { "insertAdjacentHTML", &DOMBackendDispatcher::insertAdjacentHTML },
            { "performSearch", &DOMBackendDispatcher::performSearch },
            { "getSearchResults", &DOMBackendDispatcher::getSearchResults },
            { "discardSearchResults", &DOMBackendDispatcher::discardSearchResults },
            { "requestNode", &DOMBackendDispatcher::requestNode },
            { "setInspectModeEnabled", &DOMBackendDispatcher::setInspectModeEnabled },
            { "highlightRect", &DOMBackendDispatcher::highlightRect },
            { "highlightQuad", &DOMBackendDispatcher::highlightQuad },
            { "highlightSelector", &DOMBackendDispatcher::highlightSelector },
            { "highlightNode", &DOMBackendDispatcher::highlightNode },
            { "highlightNodeList", &DOMBackendDispatcher::highlightNodeList },
            { "hideHighlight", &DOMBackendDispatcher::hideHighlight },
            { "highlightFrame", &DOMBackendDispatcher::highlightFrame },
            { "pushNodeByPathToFrontend", &DOMBackendDispatcher::pushNodeByPathToFrontend },
            { "resolveNode", &DOMBackendDispatcher::resolveNode },
            { "getAttributes", &DOMBackendDispatcher::getAttributes },
            { "moveTo", &DOMBackendDispatcher::moveTo },
            { "undo", &DOMBackendDispatcher::undo },
            { "redo", &DOMBackendDispatcher::redo },
            { "markUndoableState", &DOMBackendDispatcher::markUndoableState },
            { "focus", &DOMBackendDispatcher::focus },
            { "setInspectedNode", &DOMBackendDispatcher::setInspectedNode },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'DOM." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void DOMBackendDispatcher::getDocument(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getDocument(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::DOM::Node> out_root;
    m_agent->getDocument(error, out_root);

    if (!error.length())
        result->setObject("root"_s, out_root);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::requestChildNodes(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    bool opt_in_depth_valueFound = false;
    int opt_in_depth = m_backendDispatcher->getInteger(parameters.get(), "depth"_s, &opt_in_depth_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.requestChildNodes' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestChildNodes(requestId, in_nodeId, opt_in_depth_valueFound ? &opt_in_depth : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->requestChildNodes(error, in_nodeId, opt_in_depth_valueFound ? &opt_in_depth : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::querySelector(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_selector = m_backendDispatcher->getString(parameters.get(), "selector"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.querySelector' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->querySelector(requestId, in_nodeId, in_selector);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    int out_nodeId;
    m_agent->querySelector(error, in_nodeId, in_selector, &out_nodeId);

    if (!error.length())
        result->setInteger("nodeId"_s, out_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::querySelectorAll(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_selector = m_backendDispatcher->getString(parameters.get(), "selector"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.querySelectorAll' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->querySelectorAll(requestId, in_nodeId, in_selector);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<int>> out_nodeIds;
    m_agent->querySelectorAll(error, in_nodeId, in_selector, out_nodeIds);

    if (!error.length())
        result->setArray("nodeIds"_s, out_nodeIds);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setNodeName(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_name = m_backendDispatcher->getString(parameters.get(), "name"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setNodeName' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setNodeName(requestId, in_nodeId, in_name);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    int out_nodeId;
    m_agent->setNodeName(error, in_nodeId, in_name, &out_nodeId);

    if (!error.length())
        result->setInteger("nodeId"_s, out_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setNodeValue(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_value = m_backendDispatcher->getString(parameters.get(), "value"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setNodeValue' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setNodeValue(requestId, in_nodeId, in_value);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setNodeValue(error, in_nodeId, in_value);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::removeNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.removeNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeNode(error, in_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setAttributeValue(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_name = m_backendDispatcher->getString(parameters.get(), "name"_s, nullptr);
    String in_value = m_backendDispatcher->getString(parameters.get(), "value"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setAttributeValue' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setAttributeValue(requestId, in_nodeId, in_name, in_value);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setAttributeValue(error, in_nodeId, in_name, in_value);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setAttributesAsText(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_text = m_backendDispatcher->getString(parameters.get(), "text"_s, nullptr);
    bool opt_in_name_valueFound = false;
    String opt_in_name = m_backendDispatcher->getString(parameters.get(), "name"_s, &opt_in_name_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setAttributesAsText' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setAttributesAsText(requestId, in_nodeId, in_text, opt_in_name_valueFound ? &opt_in_name : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setAttributesAsText(error, in_nodeId, in_text, opt_in_name_valueFound ? &opt_in_name : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::removeAttribute(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_name = m_backendDispatcher->getString(parameters.get(), "name"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.removeAttribute' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeAttribute(requestId, in_nodeId, in_name);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeAttribute(error, in_nodeId, in_name);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getSupportedEventNames(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getSupportedEventNames(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<String>> out_eventNames;
    m_agent->getSupportedEventNames(error, out_eventNames);

    if (!error.length())
        result->setArray("eventNames"_s, out_eventNames);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getDataBindingsForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getDataBindingsForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getDataBindingsForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::DataBinding>> out_dataBindings;
    m_agent->getDataBindingsForNode(error, in_nodeId, out_dataBindings);

    if (!error.length())
        result->setArray("dataBindings"_s, out_dataBindings);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getAssociatedDataForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getAssociatedDataForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getAssociatedDataForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    Optional<String> out_associatedData;
    m_agent->getAssociatedDataForNode(error, in_nodeId, out_associatedData);

    if (!error.length())
        if (out_associatedData.hasValue())
            result->setString("associatedData"_s, *out_associatedData);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getEventListenersForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getEventListenersForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getEventListenersForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::EventListener>> out_listeners;
    m_agent->getEventListenersForNode(error, in_nodeId, out_listeners);

    if (!error.length())
        result->setArray("listeners"_s, out_listeners);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setEventListenerDisabled(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_eventListenerId = m_backendDispatcher->getInteger(parameters.get(), "eventListenerId"_s, nullptr);
    bool in_disabled = m_backendDispatcher->getBoolean(parameters.get(), "disabled"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setEventListenerDisabled' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setEventListenerDisabled(requestId, in_eventListenerId, in_disabled);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setEventListenerDisabled(error, in_eventListenerId, in_disabled);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setBreakpointForEventListener(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_eventListenerId = m_backendDispatcher->getInteger(parameters.get(), "eventListenerId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setBreakpointForEventListener' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setBreakpointForEventListener(requestId, in_eventListenerId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setBreakpointForEventListener(error, in_eventListenerId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::removeBreakpointForEventListener(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_eventListenerId = m_backendDispatcher->getInteger(parameters.get(), "eventListenerId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.removeBreakpointForEventListener' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeBreakpointForEventListener(requestId, in_eventListenerId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeBreakpointForEventListener(error, in_eventListenerId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getAccessibilityPropertiesForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getAccessibilityPropertiesForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getAccessibilityPropertiesForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> out_properties;
    m_agent->getAccessibilityPropertiesForNode(error, in_nodeId, out_properties);

    if (!error.length())
        result->setObject("properties"_s, out_properties);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getOuterHTML(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getOuterHTML' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getOuterHTML(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_outerHTML;
    m_agent->getOuterHTML(error, in_nodeId, &out_outerHTML);

    if (!error.length())
        result->setString("outerHTML"_s, out_outerHTML);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setOuterHTML(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_outerHTML = m_backendDispatcher->getString(parameters.get(), "outerHTML"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setOuterHTML' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setOuterHTML(requestId, in_nodeId, in_outerHTML);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setOuterHTML(error, in_nodeId, in_outerHTML);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::insertAdjacentHTML(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_position = m_backendDispatcher->getString(parameters.get(), "position"_s, nullptr);
    String in_html = m_backendDispatcher->getString(parameters.get(), "html"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.insertAdjacentHTML' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->insertAdjacentHTML(requestId, in_nodeId, in_position, in_html);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->insertAdjacentHTML(error, in_nodeId, in_position, in_html);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::performSearch(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_query = m_backendDispatcher->getString(parameters.get(), "query"_s, nullptr);
    bool opt_in_nodeIds_valueFound = false;
    RefPtr<JSON::Array> opt_in_nodeIds = m_backendDispatcher->getArray(parameters.get(), "nodeIds"_s, &opt_in_nodeIds_valueFound);
    bool opt_in_caseSensitive_valueFound = false;
    bool opt_in_caseSensitive = m_backendDispatcher->getBoolean(parameters.get(), "caseSensitive"_s, &opt_in_caseSensitive_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.performSearch' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->performSearch(requestId, in_query, opt_in_nodeIds_valueFound ? opt_in_nodeIds.get() : nullptr, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_searchId;
    int out_resultCount;
    m_agent->performSearch(error, in_query, opt_in_nodeIds_valueFound ? opt_in_nodeIds.get() : nullptr, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, &out_searchId, &out_resultCount);

    if (!error.length()) {
        result->setString("searchId"_s, out_searchId);
        result->setInteger("resultCount"_s, out_resultCount);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getSearchResults(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_searchId = m_backendDispatcher->getString(parameters.get(), "searchId"_s, nullptr);
    int in_fromIndex = m_backendDispatcher->getInteger(parameters.get(), "fromIndex"_s, nullptr);
    int in_toIndex = m_backendDispatcher->getInteger(parameters.get(), "toIndex"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getSearchResults' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getSearchResults(requestId, in_searchId, in_fromIndex, in_toIndex);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<int>> out_nodeIds;
    m_agent->getSearchResults(error, in_searchId, in_fromIndex, in_toIndex, out_nodeIds);

    if (!error.length())
        result->setArray("nodeIds"_s, out_nodeIds);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::discardSearchResults(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_searchId = m_backendDispatcher->getString(parameters.get(), "searchId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.discardSearchResults' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->discardSearchResults(requestId, in_searchId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->discardSearchResults(error, in_searchId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::requestNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.requestNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestNode(requestId, in_objectId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    int out_nodeId;
    m_agent->requestNode(error, in_objectId, &out_nodeId);

    if (!error.length())
        result->setInteger("nodeId"_s, out_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setInspectModeEnabled(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_enabled = m_backendDispatcher->getBoolean(parameters.get(), "enabled"_s, nullptr);
    bool opt_in_highlightConfig_valueFound = false;
    RefPtr<JSON::Object> opt_in_highlightConfig = m_backendDispatcher->getObject(parameters.get(), "highlightConfig"_s, &opt_in_highlightConfig_valueFound);
    bool opt_in_showRulers_valueFound = false;
    bool opt_in_showRulers = m_backendDispatcher->getBoolean(parameters.get(), "showRulers"_s, &opt_in_showRulers_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setInspectModeEnabled' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setInspectModeEnabled(requestId, in_enabled, opt_in_highlightConfig_valueFound ? opt_in_highlightConfig.get() : nullptr, opt_in_showRulers_valueFound ? &opt_in_showRulers : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setInspectModeEnabled(error, in_enabled, opt_in_highlightConfig_valueFound ? opt_in_highlightConfig.get() : nullptr, opt_in_showRulers_valueFound ? &opt_in_showRulers : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::highlightRect(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_x = m_backendDispatcher->getInteger(parameters.get(), "x"_s, nullptr);
    int in_y = m_backendDispatcher->getInteger(parameters.get(), "y"_s, nullptr);
    int in_width = m_backendDispatcher->getInteger(parameters.get(), "width"_s, nullptr);
    int in_height = m_backendDispatcher->getInteger(parameters.get(), "height"_s, nullptr);
    bool opt_in_color_valueFound = false;
    RefPtr<JSON::Object> opt_in_color = m_backendDispatcher->getObject(parameters.get(), "color"_s, &opt_in_color_valueFound);
    bool opt_in_outlineColor_valueFound = false;
    RefPtr<JSON::Object> opt_in_outlineColor = m_backendDispatcher->getObject(parameters.get(), "outlineColor"_s, &opt_in_outlineColor_valueFound);
    bool opt_in_usePageCoordinates_valueFound = false;
    bool opt_in_usePageCoordinates = m_backendDispatcher->getBoolean(parameters.get(), "usePageCoordinates"_s, &opt_in_usePageCoordinates_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.highlightRect' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->highlightRect(requestId, in_x, in_y, in_width, in_height, opt_in_color_valueFound ? opt_in_color.get() : nullptr, opt_in_outlineColor_valueFound ? opt_in_outlineColor.get() : nullptr, opt_in_usePageCoordinates_valueFound ? &opt_in_usePageCoordinates : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->highlightRect(error, in_x, in_y, in_width, in_height, opt_in_color_valueFound ? opt_in_color.get() : nullptr, opt_in_outlineColor_valueFound ? opt_in_outlineColor.get() : nullptr, opt_in_usePageCoordinates_valueFound ? &opt_in_usePageCoordinates : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::highlightQuad(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Array> in_quad = m_backendDispatcher->getArray(parameters.get(), "quad"_s, nullptr);
    bool opt_in_color_valueFound = false;
    RefPtr<JSON::Object> opt_in_color = m_backendDispatcher->getObject(parameters.get(), "color"_s, &opt_in_color_valueFound);
    bool opt_in_outlineColor_valueFound = false;
    RefPtr<JSON::Object> opt_in_outlineColor = m_backendDispatcher->getObject(parameters.get(), "outlineColor"_s, &opt_in_outlineColor_valueFound);
    bool opt_in_usePageCoordinates_valueFound = false;
    bool opt_in_usePageCoordinates = m_backendDispatcher->getBoolean(parameters.get(), "usePageCoordinates"_s, &opt_in_usePageCoordinates_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.highlightQuad' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->highlightQuad(requestId, *in_quad, opt_in_color_valueFound ? opt_in_color.get() : nullptr, opt_in_outlineColor_valueFound ? opt_in_outlineColor.get() : nullptr, opt_in_usePageCoordinates_valueFound ? &opt_in_usePageCoordinates : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->highlightQuad(error, *in_quad, opt_in_color_valueFound ? opt_in_color.get() : nullptr, opt_in_outlineColor_valueFound ? opt_in_outlineColor.get() : nullptr, opt_in_usePageCoordinates_valueFound ? &opt_in_usePageCoordinates : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::highlightSelector(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_highlightConfig = m_backendDispatcher->getObject(parameters.get(), "highlightConfig"_s, nullptr);
    String in_selectorString = m_backendDispatcher->getString(parameters.get(), "selectorString"_s, nullptr);
    bool opt_in_frameId_valueFound = false;
    String opt_in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, &opt_in_frameId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.highlightSelector' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->highlightSelector(requestId, *in_highlightConfig, in_selectorString, opt_in_frameId_valueFound ? &opt_in_frameId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->highlightSelector(error, *in_highlightConfig, in_selectorString, opt_in_frameId_valueFound ? &opt_in_frameId : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::highlightNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_highlightConfig = m_backendDispatcher->getObject(parameters.get(), "highlightConfig"_s, nullptr);
    bool opt_in_nodeId_valueFound = false;
    int opt_in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, &opt_in_nodeId_valueFound);
    bool opt_in_objectId_valueFound = false;
    String opt_in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, &opt_in_objectId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.highlightNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->highlightNode(requestId, *in_highlightConfig, opt_in_nodeId_valueFound ? &opt_in_nodeId : nullptr, opt_in_objectId_valueFound ? &opt_in_objectId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->highlightNode(error, *in_highlightConfig, opt_in_nodeId_valueFound ? &opt_in_nodeId : nullptr, opt_in_objectId_valueFound ? &opt_in_objectId : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::highlightNodeList(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Array> in_nodeIds = m_backendDispatcher->getArray(parameters.get(), "nodeIds"_s, nullptr);
    RefPtr<JSON::Object> in_highlightConfig = m_backendDispatcher->getObject(parameters.get(), "highlightConfig"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.highlightNodeList' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->highlightNodeList(requestId, *in_nodeIds, *in_highlightConfig);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->highlightNodeList(error, *in_nodeIds, *in_highlightConfig);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::hideHighlight(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->hideHighlight(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->hideHighlight(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::highlightFrame(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    bool opt_in_contentColor_valueFound = false;
    RefPtr<JSON::Object> opt_in_contentColor = m_backendDispatcher->getObject(parameters.get(), "contentColor"_s, &opt_in_contentColor_valueFound);
    bool opt_in_contentOutlineColor_valueFound = false;
    RefPtr<JSON::Object> opt_in_contentOutlineColor = m_backendDispatcher->getObject(parameters.get(), "contentOutlineColor"_s, &opt_in_contentOutlineColor_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.highlightFrame' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->highlightFrame(requestId, in_frameId, opt_in_contentColor_valueFound ? opt_in_contentColor.get() : nullptr, opt_in_contentOutlineColor_valueFound ? opt_in_contentOutlineColor.get() : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->highlightFrame(error, in_frameId, opt_in_contentColor_valueFound ? opt_in_contentColor.get() : nullptr, opt_in_contentOutlineColor_valueFound ? opt_in_contentOutlineColor.get() : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::pushNodeByPathToFrontend(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_path = m_backendDispatcher->getString(parameters.get(), "path"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.pushNodeByPathToFrontend' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->pushNodeByPathToFrontend(requestId, in_path);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    int out_nodeId;
    m_agent->pushNodeByPathToFrontend(error, in_path, &out_nodeId);

    if (!error.length())
        result->setInteger("nodeId"_s, out_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::resolveNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.resolveNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->resolveNode(requestId, in_nodeId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_object;
    m_agent->resolveNode(error, in_nodeId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, out_object);

    if (!error.length())
        result->setObject("object"_s, out_object);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::getAttributes(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.getAttributes' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getAttributes(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<String>> out_attributes;
    m_agent->getAttributes(error, in_nodeId, out_attributes);

    if (!error.length())
        result->setArray("attributes"_s, out_attributes);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::moveTo(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    int in_targetNodeId = m_backendDispatcher->getInteger(parameters.get(), "targetNodeId"_s, nullptr);
    bool opt_in_insertBeforeNodeId_valueFound = false;
    int opt_in_insertBeforeNodeId = m_backendDispatcher->getInteger(parameters.get(), "insertBeforeNodeId"_s, &opt_in_insertBeforeNodeId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.moveTo' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->moveTo(requestId, in_nodeId, in_targetNodeId, opt_in_insertBeforeNodeId_valueFound ? &opt_in_insertBeforeNodeId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    int out_nodeId;
    m_agent->moveTo(error, in_nodeId, in_targetNodeId, opt_in_insertBeforeNodeId_valueFound ? &opt_in_insertBeforeNodeId : nullptr, &out_nodeId);

    if (!error.length())
        result->setInteger("nodeId"_s, out_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::undo(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->undo(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->undo(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::redo(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->redo(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->redo(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::markUndoableState(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->markUndoableState(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->markUndoableState(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::focus(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.focus' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->focus(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->focus(error, in_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMBackendDispatcher::setInspectedNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOM.setInspectedNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setInspectedNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setInspectedNode(error, in_nodeId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<DOMDebuggerBackendDispatcher> DOMDebuggerBackendDispatcher::create(BackendDispatcher& backendDispatcher, DOMDebuggerBackendDispatcherHandler* agent)
{
    return adoptRef(*new DOMDebuggerBackendDispatcher(backendDispatcher, agent));
}

DOMDebuggerBackendDispatcher::DOMDebuggerBackendDispatcher(BackendDispatcher& backendDispatcher, DOMDebuggerBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("DOMDebugger"_s, this);
}

void DOMDebuggerBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<DOMDebuggerBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (DOMDebuggerBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "setDOMBreakpoint", &DOMDebuggerBackendDispatcher::setDOMBreakpoint },
            { "removeDOMBreakpoint", &DOMDebuggerBackendDispatcher::removeDOMBreakpoint },
            { "setEventBreakpoint", &DOMDebuggerBackendDispatcher::setEventBreakpoint },
            { "removeEventBreakpoint", &DOMDebuggerBackendDispatcher::removeEventBreakpoint },
            { "setURLBreakpoint", &DOMDebuggerBackendDispatcher::setURLBreakpoint },
            { "removeURLBreakpoint", &DOMDebuggerBackendDispatcher::removeURLBreakpoint },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'DOMDebugger." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void DOMDebuggerBackendDispatcher::setDOMBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_type = m_backendDispatcher->getString(parameters.get(), "type"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMDebugger.setDOMBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setDOMBreakpoint(requestId, in_nodeId, in_type);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setDOMBreakpoint(error, in_nodeId, in_type);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMDebuggerBackendDispatcher::removeDOMBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    String in_type = m_backendDispatcher->getString(parameters.get(), "type"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMDebugger.removeDOMBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeDOMBreakpoint(requestId, in_nodeId, in_type);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeDOMBreakpoint(error, in_nodeId, in_type);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMDebuggerBackendDispatcher::setEventBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_breakpointType = m_backendDispatcher->getString(parameters.get(), "breakpointType"_s, nullptr);
    String in_eventName = m_backendDispatcher->getString(parameters.get(), "eventName"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMDebugger.setEventBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setEventBreakpoint(requestId, in_breakpointType, in_eventName);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setEventBreakpoint(error, in_breakpointType, in_eventName);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMDebuggerBackendDispatcher::removeEventBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_breakpointType = m_backendDispatcher->getString(parameters.get(), "breakpointType"_s, nullptr);
    String in_eventName = m_backendDispatcher->getString(parameters.get(), "eventName"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMDebugger.removeEventBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeEventBreakpoint(requestId, in_breakpointType, in_eventName);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeEventBreakpoint(error, in_breakpointType, in_eventName);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMDebuggerBackendDispatcher::setURLBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    bool opt_in_isRegex_valueFound = false;
    bool opt_in_isRegex = m_backendDispatcher->getBoolean(parameters.get(), "isRegex"_s, &opt_in_isRegex_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMDebugger.setURLBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setURLBreakpoint(requestId, in_url, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setURLBreakpoint(error, in_url, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMDebuggerBackendDispatcher::removeURLBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMDebugger.removeURLBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeURLBreakpoint(requestId, in_url);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeURLBreakpoint(error, in_url);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<DOMStorageBackendDispatcher> DOMStorageBackendDispatcher::create(BackendDispatcher& backendDispatcher, DOMStorageBackendDispatcherHandler* agent)
{
    return adoptRef(*new DOMStorageBackendDispatcher(backendDispatcher, agent));
}

DOMStorageBackendDispatcher::DOMStorageBackendDispatcher(BackendDispatcher& backendDispatcher, DOMStorageBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("DOMStorage"_s, this);
}

void DOMStorageBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<DOMStorageBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "getDOMStorageItems")
        getDOMStorageItems(requestId, WTFMove(parameters));
    else if (method == "setDOMStorageItem")
        setDOMStorageItem(requestId, WTFMove(parameters));
    else if (method == "removeDOMStorageItem")
        removeDOMStorageItem(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'DOMStorage." + method + "' was not found");
}

void DOMStorageBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMStorageBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMStorageBackendDispatcher::getDOMStorageItems(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_storageId = m_backendDispatcher->getObject(parameters.get(), "storageId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMStorage.getDOMStorageItems' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getDOMStorageItems(requestId, *in_storageId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::DOMStorage::Item>> out_entries;
    m_agent->getDOMStorageItems(error, *in_storageId, out_entries);

    if (!error.length())
        result->setArray("entries"_s, out_entries);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMStorageBackendDispatcher::setDOMStorageItem(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_storageId = m_backendDispatcher->getObject(parameters.get(), "storageId"_s, nullptr);
    String in_key = m_backendDispatcher->getString(parameters.get(), "key"_s, nullptr);
    String in_value = m_backendDispatcher->getString(parameters.get(), "value"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMStorage.setDOMStorageItem' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setDOMStorageItem(requestId, *in_storageId, in_key, in_value);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setDOMStorageItem(error, *in_storageId, in_key, in_value);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DOMStorageBackendDispatcher::removeDOMStorageItem(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_storageId = m_backendDispatcher->getObject(parameters.get(), "storageId"_s, nullptr);
    String in_key = m_backendDispatcher->getString(parameters.get(), "key"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'DOMStorage.removeDOMStorageItem' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeDOMStorageItem(requestId, *in_storageId, in_key);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeDOMStorageItem(error, *in_storageId, in_key);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<DatabaseBackendDispatcher> DatabaseBackendDispatcher::create(BackendDispatcher& backendDispatcher, DatabaseBackendDispatcherHandler* agent)
{
    return adoptRef(*new DatabaseBackendDispatcher(backendDispatcher, agent));
}

DatabaseBackendDispatcher::DatabaseBackendDispatcher(BackendDispatcher& backendDispatcher, DatabaseBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Database"_s, this);
}

void DatabaseBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<DatabaseBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "getDatabaseTableNames")
        getDatabaseTableNames(requestId, WTFMove(parameters));
    else if (method == "executeSQL")
        executeSQL(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Database." + method + "' was not found");
}

void DatabaseBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DatabaseBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DatabaseBackendDispatcher::getDatabaseTableNames(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_databaseId = m_backendDispatcher->getString(parameters.get(), "databaseId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Database.getDatabaseTableNames' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getDatabaseTableNames(requestId, in_databaseId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<String>> out_tableNames;
    m_agent->getDatabaseTableNames(error, in_databaseId, out_tableNames);

    if (!error.length())
        result->setArray("tableNames"_s, out_tableNames);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

DatabaseBackendDispatcherHandler::ExecuteSQLCallback::ExecuteSQLCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void DatabaseBackendDispatcherHandler::ExecuteSQLCallback::sendSuccess(RefPtr<JSON::ArrayOf<String>>&& columnNames, RefPtr<JSON::ArrayOf<JSON::Value>>&& values, RefPtr<Inspector::Protocol::Database::Error>&& sqlError)
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();
    if (columnNames)
        jsonMessage->setArray("columnNames"_s, columnNames);
    if (values)
        jsonMessage->setArray("values"_s, values);
    if (sqlError)
        jsonMessage->setObject("sqlError"_s, sqlError);
    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void DatabaseBackendDispatcher::executeSQL(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_databaseId = m_backendDispatcher->getString(parameters.get(), "databaseId"_s, nullptr);
    String in_query = m_backendDispatcher->getString(parameters.get(), "query"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Database.executeSQL' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->executeSQL(requestId, in_databaseId, in_query);
        return;
    }
#endif

    Ref<DatabaseBackendDispatcherHandler::ExecuteSQLCallback> callback = adoptRef(*new DatabaseBackendDispatcherHandler::ExecuteSQLCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->executeSQL(in_databaseId, in_query, callback.copyRef());

}

Ref<DebuggerBackendDispatcher> DebuggerBackendDispatcher::create(BackendDispatcher& backendDispatcher, DebuggerBackendDispatcherHandler* agent)
{
    return adoptRef(*new DebuggerBackendDispatcher(backendDispatcher, agent));
}

DebuggerBackendDispatcher::DebuggerBackendDispatcher(BackendDispatcher& backendDispatcher, DebuggerBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Debugger"_s, this);
}

void DebuggerBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<DebuggerBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (DebuggerBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &DebuggerBackendDispatcher::enable },
            { "disable", &DebuggerBackendDispatcher::disable },
            { "setAsyncStackTraceDepth", &DebuggerBackendDispatcher::setAsyncStackTraceDepth },
            { "setBreakpointsActive", &DebuggerBackendDispatcher::setBreakpointsActive },
            { "setBreakpointByUrl", &DebuggerBackendDispatcher::setBreakpointByUrl },
            { "setBreakpoint", &DebuggerBackendDispatcher::setBreakpoint },
            { "removeBreakpoint", &DebuggerBackendDispatcher::removeBreakpoint },
            { "continueUntilNextRunLoop", &DebuggerBackendDispatcher::continueUntilNextRunLoop },
            { "continueToLocation", &DebuggerBackendDispatcher::continueToLocation },
            { "stepOver", &DebuggerBackendDispatcher::stepOver },
            { "stepInto", &DebuggerBackendDispatcher::stepInto },
            { "stepOut", &DebuggerBackendDispatcher::stepOut },
            { "pause", &DebuggerBackendDispatcher::pause },
            { "resume", &DebuggerBackendDispatcher::resume },
            { "searchInContent", &DebuggerBackendDispatcher::searchInContent },
            { "getScriptSource", &DebuggerBackendDispatcher::getScriptSource },
            { "getFunctionDetails", &DebuggerBackendDispatcher::getFunctionDetails },
            { "setPauseOnExceptions", &DebuggerBackendDispatcher::setPauseOnExceptions },
            { "setPauseOnAssertions", &DebuggerBackendDispatcher::setPauseOnAssertions },
            { "setPauseForInternalScripts", &DebuggerBackendDispatcher::setPauseForInternalScripts },
            { "evaluateOnCallFrame", &DebuggerBackendDispatcher::evaluateOnCallFrame },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Debugger." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void DebuggerBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setAsyncStackTraceDepth(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_depth = m_backendDispatcher->getInteger(parameters.get(), "depth"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setAsyncStackTraceDepth' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setAsyncStackTraceDepth(requestId, in_depth);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setAsyncStackTraceDepth(error, in_depth);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setBreakpointsActive(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_active = m_backendDispatcher->getBoolean(parameters.get(), "active"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setBreakpointsActive' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setBreakpointsActive(requestId, in_active);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setBreakpointsActive(error, in_active);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setBreakpointByUrl(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_lineNumber = m_backendDispatcher->getInteger(parameters.get(), "lineNumber"_s, nullptr);
    bool opt_in_url_valueFound = false;
    String opt_in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, &opt_in_url_valueFound);
    bool opt_in_urlRegex_valueFound = false;
    String opt_in_urlRegex = m_backendDispatcher->getString(parameters.get(), "urlRegex"_s, &opt_in_urlRegex_valueFound);
    bool opt_in_columnNumber_valueFound = false;
    int opt_in_columnNumber = m_backendDispatcher->getInteger(parameters.get(), "columnNumber"_s, &opt_in_columnNumber_valueFound);
    bool opt_in_options_valueFound = false;
    RefPtr<JSON::Object> opt_in_options = m_backendDispatcher->getObject(parameters.get(), "options"_s, &opt_in_options_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setBreakpointByUrl' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setBreakpointByUrl(requestId, in_lineNumber, opt_in_url_valueFound ? &opt_in_url : nullptr, opt_in_urlRegex_valueFound ? &opt_in_urlRegex : nullptr, opt_in_columnNumber_valueFound ? &opt_in_columnNumber : nullptr, opt_in_options_valueFound ? opt_in_options.get() : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_breakpointId;
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Debugger::Location>> out_locations;
    m_agent->setBreakpointByUrl(error, in_lineNumber, opt_in_url_valueFound ? &opt_in_url : nullptr, opt_in_urlRegex_valueFound ? &opt_in_urlRegex : nullptr, opt_in_columnNumber_valueFound ? &opt_in_columnNumber : nullptr, opt_in_options_valueFound ? opt_in_options.get() : nullptr, &out_breakpointId, out_locations);

    if (!error.length()) {
        result->setString("breakpointId"_s, out_breakpointId);
        result->setArray("locations"_s, out_locations);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_location = m_backendDispatcher->getObject(parameters.get(), "location"_s, nullptr);
    bool opt_in_options_valueFound = false;
    RefPtr<JSON::Object> opt_in_options = m_backendDispatcher->getObject(parameters.get(), "options"_s, &opt_in_options_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setBreakpoint(requestId, *in_location, opt_in_options_valueFound ? opt_in_options.get() : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_breakpointId;
    RefPtr<Inspector::Protocol::Debugger::Location> out_actualLocation;
    m_agent->setBreakpoint(error, *in_location, opt_in_options_valueFound ? opt_in_options.get() : nullptr, &out_breakpointId, out_actualLocation);

    if (!error.length()) {
        result->setString("breakpointId"_s, out_breakpointId);
        result->setObject("actualLocation"_s, out_actualLocation);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::removeBreakpoint(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_breakpointId = m_backendDispatcher->getString(parameters.get(), "breakpointId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.removeBreakpoint' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->removeBreakpoint(requestId, in_breakpointId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->removeBreakpoint(error, in_breakpointId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::continueUntilNextRunLoop(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->continueUntilNextRunLoop(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->continueUntilNextRunLoop(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::continueToLocation(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_location = m_backendDispatcher->getObject(parameters.get(), "location"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.continueToLocation' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->continueToLocation(requestId, *in_location);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->continueToLocation(error, *in_location);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::stepOver(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stepOver(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stepOver(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::stepInto(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stepInto(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stepInto(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::stepOut(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stepOut(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stepOut(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::pause(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->pause(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->pause(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::resume(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->resume(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->resume(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::searchInContent(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_scriptId = m_backendDispatcher->getString(parameters.get(), "scriptId"_s, nullptr);
    String in_query = m_backendDispatcher->getString(parameters.get(), "query"_s, nullptr);
    bool opt_in_caseSensitive_valueFound = false;
    bool opt_in_caseSensitive = m_backendDispatcher->getBoolean(parameters.get(), "caseSensitive"_s, &opt_in_caseSensitive_valueFound);
    bool opt_in_isRegex_valueFound = false;
    bool opt_in_isRegex = m_backendDispatcher->getBoolean(parameters.get(), "isRegex"_s, &opt_in_isRegex_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.searchInContent' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->searchInContent(requestId, in_scriptId, in_query, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>> out_result;
    m_agent->searchInContent(error, in_scriptId, in_query, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr, out_result);

    if (!error.length())
        result->setArray("result"_s, out_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::getScriptSource(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_scriptId = m_backendDispatcher->getString(parameters.get(), "scriptId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.getScriptSource' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getScriptSource(requestId, in_scriptId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_scriptSource;
    m_agent->getScriptSource(error, in_scriptId, &out_scriptSource);

    if (!error.length())
        result->setString("scriptSource"_s, out_scriptSource);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::getFunctionDetails(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_functionId = m_backendDispatcher->getString(parameters.get(), "functionId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.getFunctionDetails' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getFunctionDetails(requestId, in_functionId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Debugger::FunctionDetails> out_details;
    m_agent->getFunctionDetails(error, in_functionId, out_details);

    if (!error.length())
        result->setObject("details"_s, out_details);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setPauseOnExceptions(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_state = m_backendDispatcher->getString(parameters.get(), "state"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setPauseOnExceptions' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setPauseOnExceptions(requestId, in_state);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setPauseOnExceptions(error, in_state);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setPauseOnAssertions(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_enabled = m_backendDispatcher->getBoolean(parameters.get(), "enabled"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setPauseOnAssertions' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setPauseOnAssertions(requestId, in_enabled);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setPauseOnAssertions(error, in_enabled);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::setPauseForInternalScripts(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_shouldPause = m_backendDispatcher->getBoolean(parameters.get(), "shouldPause"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.setPauseForInternalScripts' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setPauseForInternalScripts(requestId, in_shouldPause);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setPauseForInternalScripts(error, in_shouldPause);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void DebuggerBackendDispatcher::evaluateOnCallFrame(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_callFrameId = m_backendDispatcher->getString(parameters.get(), "callFrameId"_s, nullptr);
    String in_expression = m_backendDispatcher->getString(parameters.get(), "expression"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    bool opt_in_includeCommandLineAPI_valueFound = false;
    bool opt_in_includeCommandLineAPI = m_backendDispatcher->getBoolean(parameters.get(), "includeCommandLineAPI"_s, &opt_in_includeCommandLineAPI_valueFound);
    bool opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound = false;
    bool opt_in_doNotPauseOnExceptionsAndMuteConsole = m_backendDispatcher->getBoolean(parameters.get(), "doNotPauseOnExceptionsAndMuteConsole"_s, &opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound);
    bool opt_in_returnByValue_valueFound = false;
    bool opt_in_returnByValue = m_backendDispatcher->getBoolean(parameters.get(), "returnByValue"_s, &opt_in_returnByValue_valueFound);
    bool opt_in_generatePreview_valueFound = false;
    bool opt_in_generatePreview = m_backendDispatcher->getBoolean(parameters.get(), "generatePreview"_s, &opt_in_generatePreview_valueFound);
    bool opt_in_saveResult_valueFound = false;
    bool opt_in_saveResult = m_backendDispatcher->getBoolean(parameters.get(), "saveResult"_s, &opt_in_saveResult_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Debugger.evaluateOnCallFrame' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->evaluateOnCallFrame(requestId, in_callFrameId, in_expression, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, opt_in_includeCommandLineAPI_valueFound ? &opt_in_includeCommandLineAPI : nullptr, opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound ? &opt_in_doNotPauseOnExceptionsAndMuteConsole : nullptr, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, opt_in_saveResult_valueFound ? &opt_in_saveResult : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_result;
    Optional<bool> out_wasThrown;
    Optional<int> out_savedResultIndex;
    m_agent->evaluateOnCallFrame(error, in_callFrameId, in_expression, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, opt_in_includeCommandLineAPI_valueFound ? &opt_in_includeCommandLineAPI : nullptr, opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound ? &opt_in_doNotPauseOnExceptionsAndMuteConsole : nullptr, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, opt_in_saveResult_valueFound ? &opt_in_saveResult : nullptr, out_result, out_wasThrown, out_savedResultIndex);

    if (!error.length()) {
        result->setObject("result"_s, out_result);
        if (out_wasThrown.hasValue())
            result->setBoolean("wasThrown"_s, *out_wasThrown);
        if (out_savedResultIndex.hasValue())
            result->setInteger("savedResultIndex"_s, *out_savedResultIndex);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<HeapBackendDispatcher> HeapBackendDispatcher::create(BackendDispatcher& backendDispatcher, HeapBackendDispatcherHandler* agent)
{
    return adoptRef(*new HeapBackendDispatcher(backendDispatcher, agent));
}

HeapBackendDispatcher::HeapBackendDispatcher(BackendDispatcher& backendDispatcher, HeapBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Heap"_s, this);
}

void HeapBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<HeapBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (HeapBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &HeapBackendDispatcher::enable },
            { "disable", &HeapBackendDispatcher::disable },
            { "gc", &HeapBackendDispatcher::gc },
            { "snapshot", &HeapBackendDispatcher::snapshot },
            { "startTracking", &HeapBackendDispatcher::startTracking },
            { "stopTracking", &HeapBackendDispatcher::stopTracking },
            { "getPreview", &HeapBackendDispatcher::getPreview },
            { "getRemoteObject", &HeapBackendDispatcher::getRemoteObject },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Heap." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void HeapBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::gc(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->gc(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->gc(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::snapshot(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->snapshot(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    double out_timestamp;
    String out_snapshotData;
    m_agent->snapshot(error, &out_timestamp, &out_snapshotData);

    if (!error.length()) {
        result->setDouble("timestamp"_s, out_timestamp);
        result->setString("snapshotData"_s, out_snapshotData);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::startTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->startTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->startTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::stopTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stopTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stopTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::getPreview(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_heapObjectId = m_backendDispatcher->getInteger(parameters.get(), "heapObjectId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Heap.getPreview' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getPreview(requestId, in_heapObjectId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    Optional<String> out_string;
    RefPtr<Inspector::Protocol::Debugger::FunctionDetails> out_functionDetails;
    RefPtr<Inspector::Protocol::Runtime::ObjectPreview> out_preview;
    m_agent->getPreview(error, in_heapObjectId, out_string, out_functionDetails, out_preview);

    if (!error.length()) {
        if (out_string.hasValue())
            result->setString("string"_s, *out_string);
        if (out_functionDetails)
            result->setObject("functionDetails"_s, out_functionDetails);
        if (out_preview)
            result->setObject("preview"_s, out_preview);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void HeapBackendDispatcher::getRemoteObject(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_heapObjectId = m_backendDispatcher->getInteger(parameters.get(), "heapObjectId"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Heap.getRemoteObject' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getRemoteObject(requestId, in_heapObjectId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_result;
    m_agent->getRemoteObject(error, in_heapObjectId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, out_result);

    if (!error.length())
        result->setObject("result"_s, out_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

#if ENABLE(INDEXED_DATABASE)
Ref<IndexedDBBackendDispatcher> IndexedDBBackendDispatcher::create(BackendDispatcher& backendDispatcher, IndexedDBBackendDispatcherHandler* agent)
{
    return adoptRef(*new IndexedDBBackendDispatcher(backendDispatcher, agent));
}

IndexedDBBackendDispatcher::IndexedDBBackendDispatcher(BackendDispatcher& backendDispatcher, IndexedDBBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("IndexedDB"_s, this);
}

void IndexedDBBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<IndexedDBBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (IndexedDBBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &IndexedDBBackendDispatcher::enable },
            { "disable", &IndexedDBBackendDispatcher::disable },
            { "requestDatabaseNames", &IndexedDBBackendDispatcher::requestDatabaseNames },
            { "requestDatabase", &IndexedDBBackendDispatcher::requestDatabase },
            { "requestData", &IndexedDBBackendDispatcher::requestData },
            { "clearObjectStore", &IndexedDBBackendDispatcher::clearObjectStore },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'IndexedDB." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void IndexedDBBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void IndexedDBBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback::RequestDatabaseNamesCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback::sendSuccess(RefPtr<JSON::ArrayOf<String>>&& databaseNames)
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();
    jsonMessage->setArray("databaseNames"_s, databaseNames);
    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void IndexedDBBackendDispatcher::requestDatabaseNames(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_securityOrigin = m_backendDispatcher->getString(parameters.get(), "securityOrigin"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'IndexedDB.requestDatabaseNames' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestDatabaseNames(requestId, in_securityOrigin);
        return;
    }
#endif

    Ref<IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback> callback = adoptRef(*new IndexedDBBackendDispatcherHandler::RequestDatabaseNamesCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->requestDatabaseNames(in_securityOrigin, callback.copyRef());

}

IndexedDBBackendDispatcherHandler::RequestDatabaseCallback::RequestDatabaseCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void IndexedDBBackendDispatcherHandler::RequestDatabaseCallback::sendSuccess(RefPtr<Inspector::Protocol::IndexedDB::DatabaseWithObjectStores>&& databaseWithObjectStores)
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();
    jsonMessage->setObject("databaseWithObjectStores"_s, databaseWithObjectStores);
    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void IndexedDBBackendDispatcher::requestDatabase(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_securityOrigin = m_backendDispatcher->getString(parameters.get(), "securityOrigin"_s, nullptr);
    String in_databaseName = m_backendDispatcher->getString(parameters.get(), "databaseName"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'IndexedDB.requestDatabase' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestDatabase(requestId, in_securityOrigin, in_databaseName);
        return;
    }
#endif

    Ref<IndexedDBBackendDispatcherHandler::RequestDatabaseCallback> callback = adoptRef(*new IndexedDBBackendDispatcherHandler::RequestDatabaseCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->requestDatabase(in_securityOrigin, in_databaseName, callback.copyRef());

}

IndexedDBBackendDispatcherHandler::RequestDataCallback::RequestDataCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void IndexedDBBackendDispatcherHandler::RequestDataCallback::sendSuccess(RefPtr<JSON::ArrayOf<Inspector::Protocol::IndexedDB::DataEntry>>&& objectStoreDataEntries, bool hasMore)
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();
    jsonMessage->setArray("objectStoreDataEntries"_s, objectStoreDataEntries);
    jsonMessage->setBoolean("hasMore"_s, hasMore);
    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void IndexedDBBackendDispatcher::requestData(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_securityOrigin = m_backendDispatcher->getString(parameters.get(), "securityOrigin"_s, nullptr);
    String in_databaseName = m_backendDispatcher->getString(parameters.get(), "databaseName"_s, nullptr);
    String in_objectStoreName = m_backendDispatcher->getString(parameters.get(), "objectStoreName"_s, nullptr);
    String in_indexName = m_backendDispatcher->getString(parameters.get(), "indexName"_s, nullptr);
    int in_skipCount = m_backendDispatcher->getInteger(parameters.get(), "skipCount"_s, nullptr);
    int in_pageSize = m_backendDispatcher->getInteger(parameters.get(), "pageSize"_s, nullptr);
    bool opt_in_keyRange_valueFound = false;
    RefPtr<JSON::Object> opt_in_keyRange = m_backendDispatcher->getObject(parameters.get(), "keyRange"_s, &opt_in_keyRange_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'IndexedDB.requestData' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->requestData(requestId, in_securityOrigin, in_databaseName, in_objectStoreName, in_indexName, in_skipCount, in_pageSize, opt_in_keyRange_valueFound ? opt_in_keyRange.get() : nullptr);
        return;
    }
#endif

    Ref<IndexedDBBackendDispatcherHandler::RequestDataCallback> callback = adoptRef(*new IndexedDBBackendDispatcherHandler::RequestDataCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->requestData(in_securityOrigin, in_databaseName, in_objectStoreName, in_indexName, in_skipCount, in_pageSize, opt_in_keyRange_valueFound ? opt_in_keyRange.get() : nullptr, callback.copyRef());

}

IndexedDBBackendDispatcherHandler::ClearObjectStoreCallback::ClearObjectStoreCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void IndexedDBBackendDispatcherHandler::ClearObjectStoreCallback::sendSuccess()
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();

    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void IndexedDBBackendDispatcher::clearObjectStore(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_securityOrigin = m_backendDispatcher->getString(parameters.get(), "securityOrigin"_s, nullptr);
    String in_databaseName = m_backendDispatcher->getString(parameters.get(), "databaseName"_s, nullptr);
    String in_objectStoreName = m_backendDispatcher->getString(parameters.get(), "objectStoreName"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'IndexedDB.clearObjectStore' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->clearObjectStore(requestId, in_securityOrigin, in_databaseName, in_objectStoreName);
        return;
    }
#endif

    Ref<IndexedDBBackendDispatcherHandler::ClearObjectStoreCallback> callback = adoptRef(*new IndexedDBBackendDispatcherHandler::ClearObjectStoreCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->clearObjectStore(in_securityOrigin, in_databaseName, in_objectStoreName, callback.copyRef());

}
#endif // ENABLE(INDEXED_DATABASE)

Ref<InspectorBackendDispatcher> InspectorBackendDispatcher::create(BackendDispatcher& backendDispatcher, InspectorBackendDispatcherHandler* agent)
{
    return adoptRef(*new InspectorBackendDispatcher(backendDispatcher, agent));
}

InspectorBackendDispatcher::InspectorBackendDispatcher(BackendDispatcher& backendDispatcher, InspectorBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Inspector"_s, this);
}

void InspectorBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<InspectorBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "initialized")
        initialized(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Inspector." + method + "' was not found");
}

void InspectorBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void InspectorBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void InspectorBackendDispatcher::initialized(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->initialized(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->initialized(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<LayerTreeBackendDispatcher> LayerTreeBackendDispatcher::create(BackendDispatcher& backendDispatcher, LayerTreeBackendDispatcherHandler* agent)
{
    return adoptRef(*new LayerTreeBackendDispatcher(backendDispatcher, agent));
}

LayerTreeBackendDispatcher::LayerTreeBackendDispatcher(BackendDispatcher& backendDispatcher, LayerTreeBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("LayerTree"_s, this);
}

void LayerTreeBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<LayerTreeBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "layersForNode")
        layersForNode(requestId, WTFMove(parameters));
    else if (method == "reasonsForCompositingLayer")
        reasonsForCompositingLayer(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'LayerTree." + method + "' was not found");
}

void LayerTreeBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void LayerTreeBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void LayerTreeBackendDispatcher::layersForNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'LayerTree.layersForNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->layersForNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::LayerTree::Layer>> out_layers;
    m_agent->layersForNode(error, in_nodeId, out_layers);

    if (!error.length())
        result->setArray("layers"_s, out_layers);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void LayerTreeBackendDispatcher::reasonsForCompositingLayer(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_layerId = m_backendDispatcher->getString(parameters.get(), "layerId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'LayerTree.reasonsForCompositingLayer' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->reasonsForCompositingLayer(requestId, in_layerId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::LayerTree::CompositingReasons> out_compositingReasons;
    m_agent->reasonsForCompositingLayer(error, in_layerId, out_compositingReasons);

    if (!error.length())
        result->setObject("compositingReasons"_s, out_compositingReasons);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

#if ENABLE(RESOURCE_USAGE)
Ref<MemoryBackendDispatcher> MemoryBackendDispatcher::create(BackendDispatcher& backendDispatcher, MemoryBackendDispatcherHandler* agent)
{
    return adoptRef(*new MemoryBackendDispatcher(backendDispatcher, agent));
}

MemoryBackendDispatcher::MemoryBackendDispatcher(BackendDispatcher& backendDispatcher, MemoryBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Memory"_s, this);
}

void MemoryBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<MemoryBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "startTracking")
        startTracking(requestId, WTFMove(parameters));
    else if (method == "stopTracking")
        stopTracking(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Memory." + method + "' was not found");
}

void MemoryBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void MemoryBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void MemoryBackendDispatcher::startTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->startTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->startTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void MemoryBackendDispatcher::stopTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stopTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stopTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}
#endif // ENABLE(RESOURCE_USAGE)

Ref<NetworkBackendDispatcher> NetworkBackendDispatcher::create(BackendDispatcher& backendDispatcher, NetworkBackendDispatcherHandler* agent)
{
    return adoptRef(*new NetworkBackendDispatcher(backendDispatcher, agent));
}

NetworkBackendDispatcher::NetworkBackendDispatcher(BackendDispatcher& backendDispatcher, NetworkBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Network"_s, this);
}

void NetworkBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<NetworkBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (NetworkBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &NetworkBackendDispatcher::enable },
            { "disable", &NetworkBackendDispatcher::disable },
            { "setExtraHTTPHeaders", &NetworkBackendDispatcher::setExtraHTTPHeaders },
            { "getResponseBody", &NetworkBackendDispatcher::getResponseBody },
            { "setResourceCachingDisabled", &NetworkBackendDispatcher::setResourceCachingDisabled },
            { "loadResource", &NetworkBackendDispatcher::loadResource },
            { "getSerializedCertificate", &NetworkBackendDispatcher::getSerializedCertificate },
            { "resolveWebSocket", &NetworkBackendDispatcher::resolveWebSocket },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Network." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void NetworkBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void NetworkBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void NetworkBackendDispatcher::setExtraHTTPHeaders(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_headers = m_backendDispatcher->getObject(parameters.get(), "headers"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Network.setExtraHTTPHeaders' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setExtraHTTPHeaders(requestId, *in_headers);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setExtraHTTPHeaders(error, *in_headers);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void NetworkBackendDispatcher::getResponseBody(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_requestId = m_backendDispatcher->getString(parameters.get(), "requestId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Network.getResponseBody' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getResponseBody(requestId, in_requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_body;
    bool out_base64Encoded;
    m_agent->getResponseBody(error, in_requestId, &out_body, &out_base64Encoded);

    if (!error.length()) {
        result->setString("body"_s, out_body);
        result->setBoolean("base64Encoded"_s, out_base64Encoded);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void NetworkBackendDispatcher::setResourceCachingDisabled(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_disabled = m_backendDispatcher->getBoolean(parameters.get(), "disabled"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Network.setResourceCachingDisabled' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setResourceCachingDisabled(requestId, in_disabled);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setResourceCachingDisabled(error, in_disabled);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

NetworkBackendDispatcherHandler::LoadResourceCallback::LoadResourceCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void NetworkBackendDispatcherHandler::LoadResourceCallback::sendSuccess(const String& content, const String& mimeType, int status)
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();
    jsonMessage->setString("content"_s, content);
    jsonMessage->setString("mimeType"_s, mimeType);
    jsonMessage->setInteger("status"_s, status);
    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void NetworkBackendDispatcher::loadResource(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Network.loadResource' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->loadResource(requestId, in_frameId, in_url);
        return;
    }
#endif

    Ref<NetworkBackendDispatcherHandler::LoadResourceCallback> callback = adoptRef(*new NetworkBackendDispatcherHandler::LoadResourceCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->loadResource(in_frameId, in_url, callback.copyRef());

}

void NetworkBackendDispatcher::getSerializedCertificate(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_requestId = m_backendDispatcher->getString(parameters.get(), "requestId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Network.getSerializedCertificate' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getSerializedCertificate(requestId, in_requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_serializedCertificate;
    m_agent->getSerializedCertificate(error, in_requestId, &out_serializedCertificate);

    if (!error.length())
        result->setString("serializedCertificate"_s, out_serializedCertificate);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void NetworkBackendDispatcher::resolveWebSocket(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_requestId = m_backendDispatcher->getString(parameters.get(), "requestId"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Network.resolveWebSocket' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->resolveWebSocket(requestId, in_requestId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_object;
    m_agent->resolveWebSocket(error, in_requestId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, out_object);

    if (!error.length())
        result->setObject("object"_s, out_object);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<PageBackendDispatcher> PageBackendDispatcher::create(BackendDispatcher& backendDispatcher, PageBackendDispatcherHandler* agent)
{
    return adoptRef(*new PageBackendDispatcher(backendDispatcher, agent));
}

PageBackendDispatcher::PageBackendDispatcher(BackendDispatcher& backendDispatcher, PageBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Page"_s, this);
}

void PageBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<PageBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (PageBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "enable", &PageBackendDispatcher::enable },
            { "disable", &PageBackendDispatcher::disable },
            { "reload", &PageBackendDispatcher::reload },
            { "navigate", &PageBackendDispatcher::navigate },
            { "overrideUserAgent", &PageBackendDispatcher::overrideUserAgent },
            { "overrideSetting", &PageBackendDispatcher::overrideSetting },
            { "getCookies", &PageBackendDispatcher::getCookies },
            { "deleteCookie", &PageBackendDispatcher::deleteCookie },
            { "getResourceTree", &PageBackendDispatcher::getResourceTree },
            { "getResourceContent", &PageBackendDispatcher::getResourceContent },
            { "searchInResource", &PageBackendDispatcher::searchInResource },
            { "searchInResources", &PageBackendDispatcher::searchInResources },
            { "setShowRulers", &PageBackendDispatcher::setShowRulers },
            { "setShowPaintRects", &PageBackendDispatcher::setShowPaintRects },
            { "setEmulatedMedia", &PageBackendDispatcher::setEmulatedMedia },
            { "setForcedAppearance", &PageBackendDispatcher::setForcedAppearance },
            { "getCompositingBordersVisible", &PageBackendDispatcher::getCompositingBordersVisible },
            { "setCompositingBordersVisible", &PageBackendDispatcher::setCompositingBordersVisible },
            { "snapshotNode", &PageBackendDispatcher::snapshotNode },
            { "snapshotRect", &PageBackendDispatcher::snapshotRect },
            { "archive", &PageBackendDispatcher::archive },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Page." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void PageBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::reload(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool opt_in_ignoreCache_valueFound = false;
    bool opt_in_ignoreCache = m_backendDispatcher->getBoolean(parameters.get(), "ignoreCache"_s, &opt_in_ignoreCache_valueFound);
    bool opt_in_revalidateAllResources_valueFound = false;
    bool opt_in_revalidateAllResources = m_backendDispatcher->getBoolean(parameters.get(), "revalidateAllResources"_s, &opt_in_revalidateAllResources_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.reload' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->reload(requestId, opt_in_ignoreCache_valueFound ? &opt_in_ignoreCache : nullptr, opt_in_revalidateAllResources_valueFound ? &opt_in_revalidateAllResources : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->reload(error, opt_in_ignoreCache_valueFound ? &opt_in_ignoreCache : nullptr, opt_in_revalidateAllResources_valueFound ? &opt_in_revalidateAllResources : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::navigate(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.navigate' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->navigate(requestId, in_url);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->navigate(error, in_url);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::overrideUserAgent(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool opt_in_value_valueFound = false;
    String opt_in_value = m_backendDispatcher->getString(parameters.get(), "value"_s, &opt_in_value_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.overrideUserAgent' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->overrideUserAgent(requestId, opt_in_value_valueFound ? &opt_in_value : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->overrideUserAgent(error, opt_in_value_valueFound ? &opt_in_value : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::overrideSetting(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_setting = m_backendDispatcher->getString(parameters.get(), "setting"_s, nullptr);
    bool opt_in_value_valueFound = false;
    bool opt_in_value = m_backendDispatcher->getBoolean(parameters.get(), "value"_s, &opt_in_value_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.overrideSetting' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->overrideSetting(requestId, in_setting, opt_in_value_valueFound ? &opt_in_value : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->overrideSetting(error, in_setting, opt_in_value_valueFound ? &opt_in_value : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::getCookies(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getCookies(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::Cookie>> out_cookies;
    m_agent->getCookies(error, out_cookies);

    if (!error.length())
        result->setArray("cookies"_s, out_cookies);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::deleteCookie(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_cookieName = m_backendDispatcher->getString(parameters.get(), "cookieName"_s, nullptr);
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.deleteCookie' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->deleteCookie(requestId, in_cookieName, in_url);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->deleteCookie(error, in_cookieName, in_url);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::getResourceTree(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getResourceTree(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Page::FrameResourceTree> out_frameTree;
    m_agent->getResourceTree(error, out_frameTree);

    if (!error.length())
        result->setObject("frameTree"_s, out_frameTree);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::getResourceContent(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.getResourceContent' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getResourceContent(requestId, in_frameId, in_url);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_content;
    bool out_base64Encoded;
    m_agent->getResourceContent(error, in_frameId, in_url, &out_content, &out_base64Encoded);

    if (!error.length()) {
        result->setString("content"_s, out_content);
        result->setBoolean("base64Encoded"_s, out_base64Encoded);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::searchInResource(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_frameId = m_backendDispatcher->getString(parameters.get(), "frameId"_s, nullptr);
    String in_url = m_backendDispatcher->getString(parameters.get(), "url"_s, nullptr);
    String in_query = m_backendDispatcher->getString(parameters.get(), "query"_s, nullptr);
    bool opt_in_caseSensitive_valueFound = false;
    bool opt_in_caseSensitive = m_backendDispatcher->getBoolean(parameters.get(), "caseSensitive"_s, &opt_in_caseSensitive_valueFound);
    bool opt_in_isRegex_valueFound = false;
    bool opt_in_isRegex = m_backendDispatcher->getBoolean(parameters.get(), "isRegex"_s, &opt_in_isRegex_valueFound);
    bool opt_in_requestId_valueFound = false;
    String opt_in_requestId = m_backendDispatcher->getString(parameters.get(), "requestId"_s, &opt_in_requestId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.searchInResource' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->searchInResource(requestId, in_frameId, in_url, in_query, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr, opt_in_requestId_valueFound ? &opt_in_requestId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>> out_result;
    m_agent->searchInResource(error, in_frameId, in_url, in_query, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr, opt_in_requestId_valueFound ? &opt_in_requestId : nullptr, out_result);

    if (!error.length())
        result->setArray("result"_s, out_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::searchInResources(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_text = m_backendDispatcher->getString(parameters.get(), "text"_s, nullptr);
    bool opt_in_caseSensitive_valueFound = false;
    bool opt_in_caseSensitive = m_backendDispatcher->getBoolean(parameters.get(), "caseSensitive"_s, &opt_in_caseSensitive_valueFound);
    bool opt_in_isRegex_valueFound = false;
    bool opt_in_isRegex = m_backendDispatcher->getBoolean(parameters.get(), "isRegex"_s, &opt_in_isRegex_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.searchInResources' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->searchInResources(requestId, in_text, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>> out_result;
    m_agent->searchInResources(error, in_text, opt_in_caseSensitive_valueFound ? &opt_in_caseSensitive : nullptr, opt_in_isRegex_valueFound ? &opt_in_isRegex : nullptr, out_result);

    if (!error.length())
        result->setArray("result"_s, out_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::setShowRulers(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_result = m_backendDispatcher->getBoolean(parameters.get(), "result"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.setShowRulers' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setShowRulers(requestId, in_result);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setShowRulers(error, in_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::setShowPaintRects(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_result = m_backendDispatcher->getBoolean(parameters.get(), "result"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.setShowPaintRects' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setShowPaintRects(requestId, in_result);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setShowPaintRects(error, in_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::setEmulatedMedia(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_media = m_backendDispatcher->getString(parameters.get(), "media"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.setEmulatedMedia' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setEmulatedMedia(requestId, in_media);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setEmulatedMedia(error, in_media);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::setForcedAppearance(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_appearance = m_backendDispatcher->getString(parameters.get(), "appearance"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.setForcedAppearance' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setForcedAppearance(requestId, in_appearance);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setForcedAppearance(error, in_appearance);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::getCompositingBordersVisible(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getCompositingBordersVisible(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    bool out_result;
    m_agent->getCompositingBordersVisible(error, &out_result);

    if (!error.length())
        result->setBoolean("result"_s, out_result);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::setCompositingBordersVisible(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_visible = m_backendDispatcher->getBoolean(parameters.get(), "visible"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.setCompositingBordersVisible' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setCompositingBordersVisible(requestId, in_visible);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setCompositingBordersVisible(error, in_visible);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::snapshotNode(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_nodeId = m_backendDispatcher->getInteger(parameters.get(), "nodeId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.snapshotNode' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->snapshotNode(requestId, in_nodeId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_dataURL;
    m_agent->snapshotNode(error, in_nodeId, &out_dataURL);

    if (!error.length())
        result->setString("dataURL"_s, out_dataURL);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::snapshotRect(long requestId, RefPtr<JSON::Object>&& parameters)
{
    int in_x = m_backendDispatcher->getInteger(parameters.get(), "x"_s, nullptr);
    int in_y = m_backendDispatcher->getInteger(parameters.get(), "y"_s, nullptr);
    int in_width = m_backendDispatcher->getInteger(parameters.get(), "width"_s, nullptr);
    int in_height = m_backendDispatcher->getInteger(parameters.get(), "height"_s, nullptr);
    String in_coordinateSystem = m_backendDispatcher->getString(parameters.get(), "coordinateSystem"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Page.snapshotRect' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->snapshotRect(requestId, in_x, in_y, in_width, in_height, in_coordinateSystem);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_dataURL;
    m_agent->snapshotRect(error, in_x, in_y, in_width, in_height, in_coordinateSystem, &out_dataURL);

    if (!error.length())
        result->setString("dataURL"_s, out_dataURL);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void PageBackendDispatcher::archive(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->archive(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    String out_data;
    m_agent->archive(error, &out_data);

    if (!error.length())
        result->setString("data"_s, out_data);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<RuntimeBackendDispatcher> RuntimeBackendDispatcher::create(BackendDispatcher& backendDispatcher, RuntimeBackendDispatcherHandler* agent)
{
    return adoptRef(*new RuntimeBackendDispatcher(backendDispatcher, agent));
}

RuntimeBackendDispatcher::RuntimeBackendDispatcher(BackendDispatcher& backendDispatcher, RuntimeBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Runtime"_s, this);
}

void RuntimeBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<RuntimeBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    typedef void (RuntimeBackendDispatcher::*CallHandler)(long requestId, RefPtr<JSON::Object>&& message);
    typedef HashMap<String, CallHandler> DispatchMap;
    static NeverDestroyed<DispatchMap> dispatchMap;
    if (dispatchMap.get().isEmpty()) {
        static const struct MethodTable {
            const char* name;
            CallHandler handler;
        } commands[] = {
            { "parse", &RuntimeBackendDispatcher::parse },
            { "evaluate", &RuntimeBackendDispatcher::evaluate },
            { "awaitPromise", &RuntimeBackendDispatcher::awaitPromise },
            { "callFunctionOn", &RuntimeBackendDispatcher::callFunctionOn },
            { "getPreview", &RuntimeBackendDispatcher::getPreview },
            { "getProperties", &RuntimeBackendDispatcher::getProperties },
            { "getDisplayableProperties", &RuntimeBackendDispatcher::getDisplayableProperties },
            { "getCollectionEntries", &RuntimeBackendDispatcher::getCollectionEntries },
            { "saveResult", &RuntimeBackendDispatcher::saveResult },
            { "releaseObject", &RuntimeBackendDispatcher::releaseObject },
            { "releaseObjectGroup", &RuntimeBackendDispatcher::releaseObjectGroup },
            { "enable", &RuntimeBackendDispatcher::enable },
            { "disable", &RuntimeBackendDispatcher::disable },
            { "getRuntimeTypesForVariablesAtOffsets", &RuntimeBackendDispatcher::getRuntimeTypesForVariablesAtOffsets },
            { "enableTypeProfiler", &RuntimeBackendDispatcher::enableTypeProfiler },
            { "disableTypeProfiler", &RuntimeBackendDispatcher::disableTypeProfiler },
            { "enableControlFlowProfiler", &RuntimeBackendDispatcher::enableControlFlowProfiler },
            { "disableControlFlowProfiler", &RuntimeBackendDispatcher::disableControlFlowProfiler },
            { "getBasicBlocks", &RuntimeBackendDispatcher::getBasicBlocks },
        };
        size_t length = WTF_ARRAY_LENGTH(commands);
        for (size_t i = 0; i < length; ++i)
            dispatchMap.get().add(commands[i].name, commands[i].handler);
    }

    auto findResult = dispatchMap.get().find(method);
    if (findResult == dispatchMap.get().end()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Runtime." + method + "' was not found");
        return;
    }

    ((*this).*findResult->value)(requestId, WTFMove(parameters));
}

void RuntimeBackendDispatcher::parse(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_source = m_backendDispatcher->getString(parameters.get(), "source"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.parse' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->parse(requestId, in_source);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    Inspector::Protocol::Runtime::SyntaxErrorType out_result;
    Optional<String> out_message;
    RefPtr<Inspector::Protocol::Runtime::ErrorRange> out_range;
    m_agent->parse(error, in_source, &out_result, out_message, out_range);

    if (!error.length()) {
        result->setString("result"_s, Inspector::Protocol::InspectorHelpers::getEnumConstantValue(out_result));
        if (out_message.hasValue())
            result->setString("message"_s, *out_message);
        if (out_range)
            result->setObject("range"_s, out_range);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::evaluate(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_expression = m_backendDispatcher->getString(parameters.get(), "expression"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    bool opt_in_includeCommandLineAPI_valueFound = false;
    bool opt_in_includeCommandLineAPI = m_backendDispatcher->getBoolean(parameters.get(), "includeCommandLineAPI"_s, &opt_in_includeCommandLineAPI_valueFound);
    bool opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound = false;
    bool opt_in_doNotPauseOnExceptionsAndMuteConsole = m_backendDispatcher->getBoolean(parameters.get(), "doNotPauseOnExceptionsAndMuteConsole"_s, &opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound);
    bool opt_in_contextId_valueFound = false;
    int opt_in_contextId = m_backendDispatcher->getInteger(parameters.get(), "contextId"_s, &opt_in_contextId_valueFound);
    bool opt_in_returnByValue_valueFound = false;
    bool opt_in_returnByValue = m_backendDispatcher->getBoolean(parameters.get(), "returnByValue"_s, &opt_in_returnByValue_valueFound);
    bool opt_in_generatePreview_valueFound = false;
    bool opt_in_generatePreview = m_backendDispatcher->getBoolean(parameters.get(), "generatePreview"_s, &opt_in_generatePreview_valueFound);
    bool opt_in_saveResult_valueFound = false;
    bool opt_in_saveResult = m_backendDispatcher->getBoolean(parameters.get(), "saveResult"_s, &opt_in_saveResult_valueFound);
    bool opt_in_emulateUserGesture_valueFound = false;
    bool opt_in_emulateUserGesture = m_backendDispatcher->getBoolean(parameters.get(), "emulateUserGesture"_s, &opt_in_emulateUserGesture_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.evaluate' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->evaluate(requestId, in_expression, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, opt_in_includeCommandLineAPI_valueFound ? &opt_in_includeCommandLineAPI : nullptr, opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound ? &opt_in_doNotPauseOnExceptionsAndMuteConsole : nullptr, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, opt_in_saveResult_valueFound ? &opt_in_saveResult : nullptr, opt_in_emulateUserGesture_valueFound ? &opt_in_emulateUserGesture : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_result;
    Optional<bool> out_wasThrown;
    Optional<int> out_savedResultIndex;
    m_agent->evaluate(error, in_expression, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, opt_in_includeCommandLineAPI_valueFound ? &opt_in_includeCommandLineAPI : nullptr, opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound ? &opt_in_doNotPauseOnExceptionsAndMuteConsole : nullptr, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, opt_in_saveResult_valueFound ? &opt_in_saveResult : nullptr, opt_in_emulateUserGesture_valueFound ? &opt_in_emulateUserGesture : nullptr, out_result, out_wasThrown, out_savedResultIndex);

    if (!error.length()) {
        result->setObject("result"_s, out_result);
        if (out_wasThrown.hasValue())
            result->setBoolean("wasThrown"_s, *out_wasThrown);
        if (out_savedResultIndex.hasValue())
            result->setInteger("savedResultIndex"_s, *out_savedResultIndex);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

RuntimeBackendDispatcherHandler::AwaitPromiseCallback::AwaitPromiseCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTFMove(backendDispatcher), id) { }

void RuntimeBackendDispatcherHandler::AwaitPromiseCallback::sendSuccess(RefPtr<Inspector::Protocol::Runtime::RemoteObject>&& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex)
{
    Ref<JSON::Object> jsonMessage = JSON::Object::create();
    jsonMessage->setObject("result"_s, result);
    if (wasThrown.hasValue())
        jsonMessage->setBoolean("wasThrown"_s, *wasThrown);
    if (savedResultIndex.hasValue())
        jsonMessage->setInteger("savedResultIndex"_s, *savedResultIndex);
    CallbackBase::sendSuccess(WTFMove(jsonMessage));
}

void RuntimeBackendDispatcher::awaitPromise(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_promiseObjectId = m_backendDispatcher->getString(parameters.get(), "promiseObjectId"_s, nullptr);
    bool opt_in_returnByValue_valueFound = false;
    bool opt_in_returnByValue = m_backendDispatcher->getBoolean(parameters.get(), "returnByValue"_s, &opt_in_returnByValue_valueFound);
    bool opt_in_generatePreview_valueFound = false;
    bool opt_in_generatePreview = m_backendDispatcher->getBoolean(parameters.get(), "generatePreview"_s, &opt_in_generatePreview_valueFound);
    bool opt_in_saveResult_valueFound = false;
    bool opt_in_saveResult = m_backendDispatcher->getBoolean(parameters.get(), "saveResult"_s, &opt_in_saveResult_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.awaitPromise' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->awaitPromise(requestId, in_promiseObjectId, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, opt_in_saveResult_valueFound ? &opt_in_saveResult : nullptr);
        return;
    }
#endif

    Ref<RuntimeBackendDispatcherHandler::AwaitPromiseCallback> callback = adoptRef(*new RuntimeBackendDispatcherHandler::AwaitPromiseCallback(m_backendDispatcher.copyRef(), requestId));
    m_agent->awaitPromise(in_promiseObjectId, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, opt_in_saveResult_valueFound ? &opt_in_saveResult : nullptr, callback.copyRef());

}

void RuntimeBackendDispatcher::callFunctionOn(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    String in_functionDeclaration = m_backendDispatcher->getString(parameters.get(), "functionDeclaration"_s, nullptr);
    bool opt_in_arguments_valueFound = false;
    RefPtr<JSON::Array> opt_in_arguments = m_backendDispatcher->getArray(parameters.get(), "arguments"_s, &opt_in_arguments_valueFound);
    bool opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound = false;
    bool opt_in_doNotPauseOnExceptionsAndMuteConsole = m_backendDispatcher->getBoolean(parameters.get(), "doNotPauseOnExceptionsAndMuteConsole"_s, &opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound);
    bool opt_in_returnByValue_valueFound = false;
    bool opt_in_returnByValue = m_backendDispatcher->getBoolean(parameters.get(), "returnByValue"_s, &opt_in_returnByValue_valueFound);
    bool opt_in_generatePreview_valueFound = false;
    bool opt_in_generatePreview = m_backendDispatcher->getBoolean(parameters.get(), "generatePreview"_s, &opt_in_generatePreview_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.callFunctionOn' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->callFunctionOn(requestId, in_objectId, in_functionDeclaration, opt_in_arguments_valueFound ? opt_in_arguments.get() : nullptr, opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound ? &opt_in_doNotPauseOnExceptionsAndMuteConsole : nullptr, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::RemoteObject> out_result;
    Optional<bool> out_wasThrown;
    m_agent->callFunctionOn(error, in_objectId, in_functionDeclaration, opt_in_arguments_valueFound ? opt_in_arguments.get() : nullptr, opt_in_doNotPauseOnExceptionsAndMuteConsole_valueFound ? &opt_in_doNotPauseOnExceptionsAndMuteConsole : nullptr, opt_in_returnByValue_valueFound ? &opt_in_returnByValue : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, out_result, out_wasThrown);

    if (!error.length()) {
        result->setObject("result"_s, out_result);
        if (out_wasThrown.hasValue())
            result->setBoolean("wasThrown"_s, *out_wasThrown);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::getPreview(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.getPreview' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getPreview(requestId, in_objectId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::Runtime::ObjectPreview> out_preview;
    m_agent->getPreview(error, in_objectId, out_preview);

    if (!error.length())
        result->setObject("preview"_s, out_preview);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::getProperties(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    bool opt_in_ownProperties_valueFound = false;
    bool opt_in_ownProperties = m_backendDispatcher->getBoolean(parameters.get(), "ownProperties"_s, &opt_in_ownProperties_valueFound);
    bool opt_in_generatePreview_valueFound = false;
    bool opt_in_generatePreview = m_backendDispatcher->getBoolean(parameters.get(), "generatePreview"_s, &opt_in_generatePreview_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.getProperties' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getProperties(requestId, in_objectId, opt_in_ownProperties_valueFound ? &opt_in_ownProperties : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::PropertyDescriptor>> out_result;
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::InternalPropertyDescriptor>> out_internalProperties;
    m_agent->getProperties(error, in_objectId, opt_in_ownProperties_valueFound ? &opt_in_ownProperties : nullptr, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, out_result, out_internalProperties);

    if (!error.length()) {
        result->setArray("result"_s, out_result);
        if (out_internalProperties)
            result->setArray("internalProperties"_s, out_internalProperties);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::getDisplayableProperties(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    bool opt_in_generatePreview_valueFound = false;
    bool opt_in_generatePreview = m_backendDispatcher->getBoolean(parameters.get(), "generatePreview"_s, &opt_in_generatePreview_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.getDisplayableProperties' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getDisplayableProperties(requestId, in_objectId, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::PropertyDescriptor>> out_properties;
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::InternalPropertyDescriptor>> out_internalProperties;
    m_agent->getDisplayableProperties(error, in_objectId, opt_in_generatePreview_valueFound ? &opt_in_generatePreview : nullptr, out_properties, out_internalProperties);

    if (!error.length()) {
        result->setArray("properties"_s, out_properties);
        if (out_internalProperties)
            result->setArray("internalProperties"_s, out_internalProperties);
    }
    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::getCollectionEntries(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    bool opt_in_objectGroup_valueFound = false;
    String opt_in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, &opt_in_objectGroup_valueFound);
    bool opt_in_startIndex_valueFound = false;
    int opt_in_startIndex = m_backendDispatcher->getInteger(parameters.get(), "startIndex"_s, &opt_in_startIndex_valueFound);
    bool opt_in_numberToFetch_valueFound = false;
    int opt_in_numberToFetch = m_backendDispatcher->getInteger(parameters.get(), "numberToFetch"_s, &opt_in_numberToFetch_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.getCollectionEntries' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getCollectionEntries(requestId, in_objectId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, opt_in_startIndex_valueFound ? &opt_in_startIndex : nullptr, opt_in_numberToFetch_valueFound ? &opt_in_numberToFetch : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::CollectionEntry>> out_entries;
    m_agent->getCollectionEntries(error, in_objectId, opt_in_objectGroup_valueFound ? &opt_in_objectGroup : nullptr, opt_in_startIndex_valueFound ? &opt_in_startIndex : nullptr, opt_in_numberToFetch_valueFound ? &opt_in_numberToFetch : nullptr, out_entries);

    if (!error.length())
        result->setArray("entries"_s, out_entries);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::saveResult(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Object> in_value = m_backendDispatcher->getObject(parameters.get(), "value"_s, nullptr);
    bool opt_in_contextId_valueFound = false;
    int opt_in_contextId = m_backendDispatcher->getInteger(parameters.get(), "contextId"_s, &opt_in_contextId_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.saveResult' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->saveResult(requestId, *in_value, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    Optional<int> out_savedResultIndex;
    m_agent->saveResult(error, *in_value, opt_in_contextId_valueFound ? &opt_in_contextId : nullptr, out_savedResultIndex);

    if (!error.length())
        if (out_savedResultIndex.hasValue())
            result->setInteger("savedResultIndex"_s, *out_savedResultIndex);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::releaseObject(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectId = m_backendDispatcher->getString(parameters.get(), "objectId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.releaseObject' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->releaseObject(requestId, in_objectId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->releaseObject(error, in_objectId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::releaseObjectGroup(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_objectGroup = m_backendDispatcher->getString(parameters.get(), "objectGroup"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.releaseObjectGroup' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->releaseObjectGroup(requestId, in_objectGroup);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->releaseObjectGroup(error, in_objectGroup);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::getRuntimeTypesForVariablesAtOffsets(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Array> in_locations = m_backendDispatcher->getArray(parameters.get(), "locations"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.getRuntimeTypesForVariablesAtOffsets' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getRuntimeTypesForVariablesAtOffsets(requestId, *in_locations);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::TypeDescription>> out_types;
    m_agent->getRuntimeTypesForVariablesAtOffsets(error, *in_locations, out_types);

    if (!error.length())
        result->setArray("types"_s, out_types);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::enableTypeProfiler(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enableTypeProfiler(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enableTypeProfiler(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::disableTypeProfiler(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disableTypeProfiler(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disableTypeProfiler(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::enableControlFlowProfiler(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enableControlFlowProfiler(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enableControlFlowProfiler(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::disableControlFlowProfiler(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disableControlFlowProfiler(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disableControlFlowProfiler(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void RuntimeBackendDispatcher::getBasicBlocks(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_sourceID = m_backendDispatcher->getString(parameters.get(), "sourceID"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Runtime.getBasicBlocks' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getBasicBlocks(requestId, in_sourceID);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<JSON::ArrayOf<Inspector::Protocol::Runtime::BasicBlock>> out_basicBlocks;
    m_agent->getBasicBlocks(error, in_sourceID, out_basicBlocks);

    if (!error.length())
        result->setArray("basicBlocks"_s, out_basicBlocks);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<ScriptProfilerBackendDispatcher> ScriptProfilerBackendDispatcher::create(BackendDispatcher& backendDispatcher, ScriptProfilerBackendDispatcherHandler* agent)
{
    return adoptRef(*new ScriptProfilerBackendDispatcher(backendDispatcher, agent));
}

ScriptProfilerBackendDispatcher::ScriptProfilerBackendDispatcher(BackendDispatcher& backendDispatcher, ScriptProfilerBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("ScriptProfiler"_s, this);
}

void ScriptProfilerBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<ScriptProfilerBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "startTracking")
        startTracking(requestId, WTFMove(parameters));
    else if (method == "stopTracking")
        stopTracking(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'ScriptProfiler." + method + "' was not found");
}

void ScriptProfilerBackendDispatcher::startTracking(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool opt_in_includeSamples_valueFound = false;
    bool opt_in_includeSamples = m_backendDispatcher->getBoolean(parameters.get(), "includeSamples"_s, &opt_in_includeSamples_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'ScriptProfiler.startTracking' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->startTracking(requestId, opt_in_includeSamples_valueFound ? &opt_in_includeSamples : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->startTracking(error, opt_in_includeSamples_valueFound ? &opt_in_includeSamples : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void ScriptProfilerBackendDispatcher::stopTracking(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stopTracking(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stopTracking(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<ServiceWorkerBackendDispatcher> ServiceWorkerBackendDispatcher::create(BackendDispatcher& backendDispatcher, ServiceWorkerBackendDispatcherHandler* agent)
{
    return adoptRef(*new ServiceWorkerBackendDispatcher(backendDispatcher, agent));
}

ServiceWorkerBackendDispatcher::ServiceWorkerBackendDispatcher(BackendDispatcher& backendDispatcher, ServiceWorkerBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("ServiceWorker"_s, this);
}

void ServiceWorkerBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<ServiceWorkerBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "getInitializationInfo")
        getInitializationInfo(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'ServiceWorker." + method + "' was not found");
}

void ServiceWorkerBackendDispatcher::getInitializationInfo(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->getInitializationInfo(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    RefPtr<Inspector::Protocol::ServiceWorker::Configuration> out_info;
    m_agent->getInitializationInfo(error, out_info);

    if (!error.length())
        result->setObject("info"_s, out_info);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<TargetBackendDispatcher> TargetBackendDispatcher::create(BackendDispatcher& backendDispatcher, TargetBackendDispatcherHandler* agent)
{
    return adoptRef(*new TargetBackendDispatcher(backendDispatcher, agent));
}

TargetBackendDispatcher::TargetBackendDispatcher(BackendDispatcher& backendDispatcher, TargetBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Target"_s, this);
}

void TargetBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<TargetBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "exists")
        exists(requestId, WTFMove(parameters));
    else if (method == "sendMessageToTarget")
        sendMessageToTarget(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Target." + method + "' was not found");
}

void TargetBackendDispatcher::exists(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->exists(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->exists(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void TargetBackendDispatcher::sendMessageToTarget(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_targetId = m_backendDispatcher->getString(parameters.get(), "targetId"_s, nullptr);
    String in_message = m_backendDispatcher->getString(parameters.get(), "message"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Target.sendMessageToTarget' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->sendMessageToTarget(requestId, in_targetId, in_message);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->sendMessageToTarget(error, in_targetId, in_message);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<TimelineBackendDispatcher> TimelineBackendDispatcher::create(BackendDispatcher& backendDispatcher, TimelineBackendDispatcherHandler* agent)
{
    return adoptRef(*new TimelineBackendDispatcher(backendDispatcher, agent));
}

TimelineBackendDispatcher::TimelineBackendDispatcher(BackendDispatcher& backendDispatcher, TimelineBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Timeline"_s, this);
}

void TimelineBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<TimelineBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "start")
        start(requestId, WTFMove(parameters));
    else if (method == "stop")
        stop(requestId, WTFMove(parameters));
    else if (method == "setAutoCaptureEnabled")
        setAutoCaptureEnabled(requestId, WTFMove(parameters));
    else if (method == "setInstruments")
        setInstruments(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Timeline." + method + "' was not found");
}

void TimelineBackendDispatcher::start(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool opt_in_maxCallStackDepth_valueFound = false;
    int opt_in_maxCallStackDepth = m_backendDispatcher->getInteger(parameters.get(), "maxCallStackDepth"_s, &opt_in_maxCallStackDepth_valueFound);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Timeline.start' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->start(requestId, opt_in_maxCallStackDepth_valueFound ? &opt_in_maxCallStackDepth : nullptr);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->start(error, opt_in_maxCallStackDepth_valueFound ? &opt_in_maxCallStackDepth : nullptr);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void TimelineBackendDispatcher::stop(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->stop(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->stop(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void TimelineBackendDispatcher::setAutoCaptureEnabled(long requestId, RefPtr<JSON::Object>&& parameters)
{
    bool in_enabled = m_backendDispatcher->getBoolean(parameters.get(), "enabled"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Timeline.setAutoCaptureEnabled' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setAutoCaptureEnabled(requestId, in_enabled);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setAutoCaptureEnabled(error, in_enabled);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void TimelineBackendDispatcher::setInstruments(long requestId, RefPtr<JSON::Object>&& parameters)
{
    RefPtr<JSON::Array> in_instruments = m_backendDispatcher->getArray(parameters.get(), "instruments"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Timeline.setInstruments' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->setInstruments(requestId, *in_instruments);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->setInstruments(error, *in_instruments);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

Ref<WorkerBackendDispatcher> WorkerBackendDispatcher::create(BackendDispatcher& backendDispatcher, WorkerBackendDispatcherHandler* agent)
{
    return adoptRef(*new WorkerBackendDispatcher(backendDispatcher, agent));
}

WorkerBackendDispatcher::WorkerBackendDispatcher(BackendDispatcher& backendDispatcher, WorkerBackendDispatcherHandler* agent)
    : SupplementalBackendDispatcher(backendDispatcher)
    , m_agent(agent)
{
    m_backendDispatcher->registerDispatcherForDomain("Worker"_s, this);
}

void WorkerBackendDispatcher::dispatch(long requestId, const String& method, Ref<JSON::Object>&& message)
{
    Ref<WorkerBackendDispatcher> protect(*this);

    RefPtr<JSON::Object> parameters;
    message->getObject("params"_s, parameters);

    if (method == "enable")
        enable(requestId, WTFMove(parameters));
    else if (method == "disable")
        disable(requestId, WTFMove(parameters));
    else if (method == "initialized")
        initialized(requestId, WTFMove(parameters));
    else if (method == "sendMessageToWorker")
        sendMessageToWorker(requestId, WTFMove(parameters));
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::MethodNotFound, "'Worker." + method + "' was not found");
}

void WorkerBackendDispatcher::enable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->enable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->enable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void WorkerBackendDispatcher::disable(long requestId, RefPtr<JSON::Object>&&)
{
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->disable(requestId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->disable(error);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void WorkerBackendDispatcher::initialized(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_workerId = m_backendDispatcher->getString(parameters.get(), "workerId"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Worker.initialized' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->initialized(requestId, in_workerId);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->initialized(error, in_workerId);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

void WorkerBackendDispatcher::sendMessageToWorker(long requestId, RefPtr<JSON::Object>&& parameters)
{
    String in_workerId = m_backendDispatcher->getString(parameters.get(), "workerId"_s, nullptr);
    String in_message = m_backendDispatcher->getString(parameters.get(), "message"_s, nullptr);
    if (m_backendDispatcher->hasProtocolErrors()) {
        m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidParams, "Some arguments of method 'Worker.sendMessageToWorker' can't be processed"_s);
        return;
    }

#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
    if (m_alternateDispatcher) {
        m_alternateDispatcher->sendMessageToWorker(requestId, in_workerId, in_message);
        return;
    }
#endif

    ErrorString error;
    Ref<JSON::Object> result = JSON::Object::create();
    m_agent->sendMessageToWorker(error, in_workerId, in_message);

    if (!error.length())
        m_backendDispatcher->sendResponse(requestId, WTFMove(result), false);
    else
        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));
}

} // namespace Inspector
